1

在 Windows Server 2003 上,我的应用程序在全新安装时开始需要很长时间才能加载。怀疑 DLL 没有加载到它们的首选地址,这需要一些时间(应用程序有 100 多个 DLL,包括第 3 方)我运行了 sysinternals listDLLs 实用程序,要求它标记每个已重定位的 dll。奇怪的是,对于列表中的大多数 DLL,我得到如下内容:

Base        Size      Path
  ### Relocated from base of 0x44e90000:
0x44e90000  0x39000   validation.dll

也就是说:它们被标记为重定位(加载时间似乎肯定支持该理论),但它们的加载地址仍然是首选地址。

一些第三方 DLL 似乎不受此影响,但总的来说,应用程序加载的 DLL 中约有 90% 会出现这种情况。

在 Windows 7 上,似乎唯一标记的 DLL 是实际移动的 DLL,并且加载时间(如预期的那样)明显更快。

这是什么原因造成的?我怎样才能阻止它?

编辑:因为它(理论上)听起来像 ASLR 的效果,所以我检查了一下,虽然 OS DLL 确实启用了 ASLR,但我们的却不是。甚至那些也被重新定位,因此不会占用任何其他 DLL 的地址。

4

1 回答 1

1

常见,设置链接器的 /BASE 选项经常被忽略,并且在 DLL 增长时维护它是一项令人不快的维护任务。这往往不会在操作系统版本之间很好地重复,它们会在您之前加载不同的 DLL,这可能会强制重定位一个而不是另一个。此外,单个重定位可能会导致所有后续 DLL 上的一系列强制重定位。

在现代机器上,这会显着影响加载时间。重定位本身非常快,只是一个内存操作。您确实需要为重新定位的 DLL 使用的内存被提交。需要,因为原始 DLL 文件在被换出时不再适合重新加载代码,它现在由分页文件支持。如果它需要增长以适应提交大小,那么这会花费时间。这并不常见。

加载时间中更常见的问题是磁盘驱动器的速度。当您有大量 DLL 时,它们需要在冷启动时位于磁盘上。使用 100 个 DLL,这很容易花费 5 秒。当您终止程序并重新启动它时没有看到延迟时,您应该怀疑是冷启动问题。这是一个热启动,DLL 已经存在于文件系统缓存中,因此不必再次找到。解决冷启动问题需要更好的硬件,SSD 很好。或者机器学习您的使用模式,因此 SuperFetch 会在您启动程序之前为您预取 DLL。

无论如何,如果您确实怀疑有变基问题,那么您需要创建自己的内存映射以找到不会强制重定位的良好基地址。您需要一个良好的起点,了解 DLL 的加载顺序和大小。你可以从 VS 调试器中得到它。Output 窗口显示加载顺序,Debug + Windows + Modules 窗口显示 DLL 大小。链接器支持在 /BASE 选项中为基地址指定 .txt 文件,这是执行此操作的最佳方法,这样您就不必在代码不断增长的同时不断地修改单个 /BASE 值。

于 2013-12-04T12:56:07.253 回答