为什么动态链接导入(在 Windows 中)总是在应用程序启动时加载?

Why do dynamically linked imports (in Windows) always load at application start up time?

动态链接到库的一个好处是,当调用该库中的函数时,它会加载到程序的虚拟地址 space 中,然后调用该函数。静态链接加载整个可执行文件,占用 space.

在 windows 上,当程序正在加载时,所有函数导入甚至在调用程序入口点之前就已解析。例如:kernel32.dll!VirtualFree。加载所有需要的库,然后调用程序的入口点。

这与静态链接的可执行文件有何不同?如果一次加载所有引用的库,它不会占用相同数量的 space 吗?有什么好处?请帮助我理解。

事实上,不是对于所有 Windows 应用程序依赖于在启动时加载。自 Visual C++ 6.0 (1998) 以来, MS linker has supported the /DELAYLOAD option 延迟 DLL 的加载,直到并且除非它的导出之一被调用。

默认行为是在启动时加载 DLL。我假设你想知道 该默认行为如何在以下方面与链接静态库进行权衡 内存占用,更普遍。

假设具有相同实现的相同API被构建为静态 库 libfoo.lib 和动态库 libfoo.dll.

只要在给定时间只有一个程序需要libfoo.dll,那么至少 那时消耗的内存与同一程序消耗的内存一样多 它与 libfoo.lib.

静态链接

其实加载DLL的程序版本是相当有可能消耗更多内存的 比与静态库链接的那个。这是因为当为 第一次,整个 DLL被加载到内存中。但事实上,当程序链接到静态库时,不是情况,整个静态库必须合并到可执行文件。 static library 只是目标文件的存档,链接器从中 默认情况下只提取那些定义程序引用的符号, 并将 它们 链接到程序中,忽略其余部分。因此,如果程序不需要 libfoo.lib 中归档的所有目标文件, 那么静态链接 libfoo.lib 所需的内存将 更小 比动态链接 libfoo.dll.

所需的内存要多

但是,内存成本越多,越有利于 DLL 一个 运行ning 程序同时需要 libfoo.dll。那是 因为 DLL 由加载程序可以单独加载的不同代码和数据部分组成。 每个需要 libfoo.dll 的并发程序都需要有自己的副本 DLL 的 data,但它们都可以执行其 code 的相同副本。后 libfoo.dll - 代码和数据部分 - 已首次加载 需要它的程序,加载程序只需要加载其 data 的新副本 对于需要它的任何更多并发程序。

所以当我们考虑整个 运行ning 系统的内存占用时,其中 许多并发进程可能需要单个库提供的服务, 在 DLL 而不是静态库中实现此类服务是经济的 策略。

DLL 的主要目的是以一种只有一个副本的方式提供服务 无论有多少并发程序,都必须加载的实现代码 正在执行它。

但是它们还有另一个重要的好处,即使对于图书馆来说也是如此 只可能被一个应用程序使用。 foo 库的新版本发布时 制作,提供错误修复或增强功能,这是部署此版本的唯一方法 与静态库链接的程序 libfoo.lib 是 重新链接、重新分发和重新安装所有这些程序。但只要是新的 libfoo 的发布保留了现有的 API,根本不需要做任何事情 与 libfoo.dll 链接的程序。只需要 分发并安装 libfoo.dll 的新版本,这些程序将 下次他们 运行 时加载它。应用程序架构师可以选择 在 DLL 中精确地实现 特定于应用程序 功能的模块 可以部署此功能的更新,而无需最终用户 重新安装应用程序。