何时使用动态链接和静态链接2023版

引入

随着现实生活中的设备性能越来越强,CPU主频变高核数变多,内存也越来越大,如何链接依赖库越来越少的考虑性能因素了。我这里结合工作经验谈一下兼容性因素、热更新因素和许可证因素。

性能因素

参见这篇转载的原文何时使用动态链接和静态链接

兼容性因素

我相信大部分开发者的工作范围是开发应用和服务,再少一部分才是开发SDK,几乎没有人做操作系统发行版的开发。无论是应用还是SDK,都需要面对复杂的最终用户环境。这会带来动态库加载路径问题、动态库符号冲突问题。在这种场景下使用静态库是较好的选择。

用静态库解决动态库加载路径问题

动态库加载路径问题是较为常见的问题之一。例如当应用作为子进程启动时,父进程的环境变量设置可能导致动态库加载路径的优先级和位置发生变化,导致找不到动态库。其现象可能为应用可以单独正常启动,但是使用其他程序调起时却不能正常工作。路径问题也会导致加载了错误的动态库,其现象可能为应用启动时正常运行,但是执行到库中的调用时发生各种异常现象。比如系统库或加载路径更高优先级的目录中包含有应用自带的同名动态库,符号类似但版本不同。

面对最终应用的路径问题,用静态库就可以解决,即不在运行时依赖动态库的符号,而是在编译时就把符号都填充好。

用符号隐藏解决动态库符号错误问题

对于SDK开发者来说,这是不够的。事实上经验不够丰富的SDK开发者往往发现,尽管自己在构建SDK的动态库时,通用的第三方依赖库,如zlib, libcurl, openssl等已经通过静态库链接上,但是客户集成SDK后,仍然存在部分最终用户出现因符号错误导致的稀奇古怪崩溃的情况。如客户也使用了zlib, libcurl, openssl但其版本不完全相同,导致最终应用无法启动或可以启动但部分调用会崩溃的情况。这种崩溃往往难以排查,因为即使你使用了类似bugly的崩溃分析工具并且上传了正确的编译时符号,但是崩溃点大部分都是毫无意义的无法解析的符号,或者无法理解到的奇怪调用。其原因在于SDK调用的第三方库的符号不是你在编译时提供的符号,而是应用开发者提供的符号。绝大部分操作系统默认配置是在进程中的符号被满足后,就不再加载同名符号,并且也不报错。而你用你编译的第三方库的符号去解释客户第三方库的运行崩溃栈,自然是不能得到有效的结果。此时你会有疑惑,为什么明明SDK动态库中的第三方库已经链接好了静态库解填充好了符号,却仍然加载了客户提供的符号呢?这是因为作为动态库,默认情况下不知道哪些符号需要被调用,因此暴露所有符号。这个行为在mingw编译的Windows DLL动态库和linux/macOS/Android上都是如此。因此SDK对某个方法的调用,并不是直接跳转到动态库内的某个固定地址,而是先去查找进程的符号表,再对符号表中的地址进行调用。所以,需要做符号隐藏,在编译时指定需要外部调用的方法,即提供完整的需要暴露的符号表,这样就可以解决SDK动态库符号错误的问题。

热更新因素

热更新技术基本上在需要进程不停止的情况下比较实用,例如服务开发。通过进程动态加载卸载动态库,再动态加载卸载符号,可以实现服务不停但模块实现更新。需要认识到的是,这个功能虽然看起来很性感,但是维护这个功能所消耗的成本是不低的,况且配合部署架构设计,不见得就非得用单个实例不停机来解决服务不中断进行更新的问题。另外服务型应用真的还就是性能敏感型应用,使用时需要注意如果是核心模块反复调用有性能问题,那就不能使用。我的倾向是如果某些成熟框架型服务软件已经具备了这个功能,且性能不构成问题,建议使用;如果是自己开发,且投入产出比不够高,就不建议使用。这个方法在客户端几乎不可用,iOS平台是明确禁止使用dlopen加载非安装包提供的动态库,其他平台虽然没有明令禁止,但各种应用市场从自身商业利益考虑,在逐步以「不安全」的名义将热更新行为禁止掉。

许可证因素

随着软件开发行业逐步走向成熟,其利润率越来越低,对于投入产出比的要求越来越高,一次性成本支出和持续维护成本支出都要求可控。因此通过提高自研率来获取所谓的可控既不经济也不可能,大量使用成熟的开源软件是不可逆转的趋势。在使用开源软件时,要注意其许可证,像MIT之类的可以放心的使用,但是诸如GPL类的许可证,就要注意了。其传染性要求「不可分割的使用」其代码的代码,一样要使用GPL进行开源。像是ffmpeg等成熟的行业库,成本考虑不可能不用,又不能乱用,如果你的公司有一定规模或希望合规,在这里必须选择使用动态库来规避商业相关的代码不得不开源的问题。通过将GPL的代码编译成单独的动态库,并将动态库的代码开源,即可满足合规要求。这里同样需要注意,如果你是SDK的开发者,将动态库的名称做区分,符号加额外前缀防止符号冲突,是不能少的步骤。

总结

动态链接和静态链接本身是技术问题,但在实践中,以解决技术问题为目的来进行技术选型,大概率会产生偏差甚至事与愿违。结合公司具体条件、外界大环境,注意解决方案的时效,可以使用的力量等选型需要服务的主要矛盾,才能做好选择。

发表评论

为防机器,验证码请直接输入4个数字1

*