• .NET跨平台实践:Linux .Net Core自宿主应用程序瘦身记


    一,.NET Core 自宿主应用程序个头有点大

    发布.NET Core应用程序有两个方式,一种是“便携式”,一种是“自宿主式”。便携式发布时,目标程序不带.net core运行环境,所以“个头”很小,可能只有几十K几百K字节,但是它需要用户的目标系统上安装.NET CORE 框架;自宿主式发布出来的程序,自带运行时和框架类库,自成一体,不需要客户机安装.NET CORE环境,部署简单方便。

    看看一个简单的“Hello World!” 控制台程序有多大:

    修改 csproj文件,添加目标系统:

    用 dotnet publish -r:linux-x64 针对linux平台发布,得到目标文件(夹),现在看看大小:

    这个Hello World 控制台程序的目标文件,总大小达到了62.2 MB!

    二,为什么.net core自宿主程序这么大

    原因有二,一是为了能在目标系统上 “独立” 运行,自宿主程序必须自带运行时,这无可厚非,二是不管是用 dotnet publish命令行发布还是用VS发布,它们都会不分青红皂白地把.net core类库整个发布到目标程序中,这正是使目标程序变大变肥的主要原因。

    下面是发布后的部分文件列表,可以看出,很多的dll与这个hello world 程序毫无关系!

    三,给 Linux .Net Core 自宿主应用程序瘦身

    为什么要给“自宿主”程序瘦身?原因是,既然发布“自宿主”程序而不是便携式程序,一般都是程序作者或厂商希望产品能有更好的独立性,更看重程序本身的完整和纯净,不喜欢附带一些乱七八糟的东西。另外,程度体积小一些,能更方便地在卡片机(如树莓派)、小型专用设备这类存贮空间不太富裕的设备上部署,在Dockeer中部署,也能大大减小映像的大小,在同样的空间中运行更多的服务。

    从前边的分析可以看出,自宿主应用程序之所有“肥大”,是因为有太多的无关的类库或Native so库造成的,只要清理掉它们,瘦身的目标就达到了。

    1,将发布的程序全部上传到Linux系统的某个文件夹,然后运行 chmod +x coretest,给coretest赋与可执行权限。(我写的这个hello word程序名叫“coretest”)。

    2,用 ./coretest 把程序运行起来:

    不要按键,让程序不要退出。

    3,查出这个进程的PID:

    再加一个终端,用 ps -ef | grep coretest 查出这个进程的PID号

    4,列出进程关联文件:

    用 sudo lsof -p PID号,列出指定进程调用/引用的文件,从列表中找出属于这个core程序依赖的类库和core Navite函数库:

    特点:路径都指向这个core程序所在的文件夹。

    下图是列表的一部分:

    从列表中,可以看出,本 coretest 程序,相关的文件有如下三类14个文件:

    1)coretes加载程序和程序集:

    coretest
    coretest.dll

    2)依赖的.net 框架程序集:

    System.Runtime.dll
    System.Console.dll
    System.Threading.dll
    System.Runtime.Extensions.dll
    System.Collections.dll

    3)运行时函数库:

    libclrjit.so
    libcoreclr.so
    libhostpolicy.so
    libhostfxr.so
    System.Native.so
    System.Globalization.Native.so
    System.Private.CoreLib.dll

    5,修改依赖文件 coretest.deps.json,对依赖行配置文件瘦身:

    打开 coretest.deps.json文件,你会发现所有的依赖库都在其中,重要的是49行开始的“runtime.linux-x64.Microsoft.NETCore.App/2.0.0”的runtimes和native两个节点,共有173个依赖项,与我们测试出来的14个依赖,整整多了近160个依赖项,这些多余的,都可以删除!

    删除后,deps.json一下子清爽了:

    6,测试依赖配置文件是否正确:

    再次用 ./coretest 运行本程序,检查依赖项是否正确。当按任意键退出程序时,出现了下边的错误。

    原来,在Console.ReadKey返回时,会调用另一个dll,而之前用lsof时读取依赖时,程序没有执行到这一步,所以没有看到有这个依赖,这个依赖被误删了。所以,得重新加到deps.json文件中。

    再次测试,程序已经完全正常。

    7,根据瘦身后的依赖关系,删除无关文件:

    要点,需要保留依赖列表文件coretest.deps.json和运行时配置文件coretest.runtimeconfig.json。

    8,再次测试程序运行情况:

    运行 ./coretest,发现出了一个问题:

    原来还差一个native 函数库,怎么办?简单,从windows发布目录中,上传到Linux的这个程序文件夹中。

    再次运行,一帆风顺,瘦身工作正式完成!

    现在看看这个程序,共计还有多少文件:

    哈哈,现在只有19个文件!比如之前的近180个文件,这个”身“瘦得厉害吧,简直是一身清爽呀!

    瘦身后,这个程序所有文件从62.2M变成了24.3m,打包压缩后,只有8.62M。

    附记:

    有的朋友可能会说,还是有点大呀,一个hello world就有19个文件24m大小,如果我司开发一个功能完整的商业应用会不会大得吓人?其实,我可以告诉你:

    一,这19个文件已经具备了.net core的关键功能,你开发更大的商业应用,不外乎再多引用了几个dll而已,能再大多少?!

    二,这个程序是自带了运行环境的,它自成一体,独立运行,不需要麻烦你和你的客户或运维人员在linux上安装安装一大堆东西,配置一大堆东西!

    三,正因为这个程序可以独立运行,那么,如果放在Docker中,对docker镜像的体积影响可以忽略,你们镜像文件不会因为需要安装什么工作环境而增大数百M的体积。

  • 相关阅读:
    【转】SqlServer Text类型字段超过8000字处理
    uniapp项目运行时一直发http://localhost:8080/sockjs-node/info?t=1462183700002请求
    【转】chrome 浏览器调用 ocx 插件
    【转】javascript检测浏览器插件
    【转】web错误代码ERR_BLOCKED_BY_RESPONSE
    我是如何将Sublime Text 4 设置成中文版
    【转】用好 Vue 中 v-for 循环的 7 种方法
    【转】JavaScript console.log %c %o %s %d %f
    [JavaScript]UMD模块
    leetcode-课程表I和课程表II
  • 原文地址:https://www.cnblogs.com/yunei/p/7436368.html
Copyright © 2020-2023  润新知