在Windows Server 2003上,我的应用程序已经开始花费很长时间来加载全新安装。怀疑DLL没有加载到他们的首选地址,这需要一些时间(应用程序有超过100个DLL,包括第三方)我运行sysinternals listDLLs实用程序,要求它标记已重新定位的每个dll。奇怪的是,对于列表中的大多数DLL,我得到这样的结果:
Base Size Path
### Relocated from base of 0x44e90000:
0x44e90000 0x39000 validation.dll
那就是:它们被标记为重新定位(并且加载时间肯定似乎支持该理论)但是它们的加载地址仍然是首选地址。
某些第三方DLL似乎不受此影响,但整体而言,这种情况发生在应用程序加载的约90%的DLL中。
在Windows 7上,似乎唯一标记的DLL是实际移动的,并且加载时间(正如预期的那样)明显更快。
造成这种情况的原因是什么?我怎么能阻止它?
编辑:因为它(理论上)听起来像ASLR的影响,我检查过,虽然操作系统DLL确实启用了ASLR,但是我们的确不是。甚至那些都被重新安置到位,因此不占用任何其他DLL的地址。
答案 0 :(得分:1)
这是非常常见,设置链接器的/ BASE选项经常被忽略,并且当DLL增长时维护它是一项令人不愉快的维护任务。这在操作系统版本之间往往不能很好地重复,它们会在你的前面加载不同的DLL,并且可以强制重定位一个而不是另一个。此外,单个重定位可能会导致所有后续DLL上的一系列强制重定位。
这对显着影响加载时间在现代机器上有点遥远。重定位本身非常快,只是一个内存操作。您确实需要为重新定位的DLL使用的内存提交付费。由于原始DLL文件不再适合在换出代码时重新加载代码,因此它现在由分页文件支持。如果需要增长以适应提交大小,则需要花费时间。这并不常见。
加载时间中更常见的问题是磁盘驱动器的速度。当你有很多DLL时,它们需要在冷启动时位于磁盘上。使用100个DLL,很容易花费5秒。当您没有在终止程序时再看到延迟并且再次启动时,您应该怀疑冷启动问题。这是一个热门的开始,DLL已经存在于文件系统缓存中,因此不必再次找到它。解决冷启动问题需要更好的硬件,SSD很不错。或者机器学习您的使用模式,以便SuperFetch在您启动程序之前为您预先获取DLL。
Anyhoo,如果你确实怀疑一个变基本问题那么你需要创建自己的内存映射来找到不强制重定位的好基地址。您需要一个良好的起点,知道DLL的加载顺序和大小。你可以从VS调试器那里得到它。 “输出”窗口显示加载顺序,“调试+ Windows +模块”窗口显示DLL大小。链接器支持在/ BASE选项中为基地址指定.txt文件,这是执行此操作的最佳方式,因此在代码不断增长时,您不必经常修改单个/ BASE值。