题
我们的应用程序在重新启动(冷启动)后启动所需的时间比已经打开一次(热启动)要多得多。
大多数(如果不是全部)差异似乎来自加载 DLL,当 DLL 位于缓存内存页面中时,它们加载速度要快得多。我们尝试使用 清除内存 模拟重新启动(因为它比实际重新启动花费的时间少得多)并得到了混合的结果,在某些机器上它似乎非常一致地模拟重新启动,而在某些机器上则不然。
总结一下我的问题是:
- 您是否经历过冷启动和热启动之间的启动时间差异?
- 您是如何应对这些差异的?
- 您知道一种可靠地模拟重新启动的方法吗?
编辑:
对评论的澄清:
- 该应用程序主要是本机 C++ 和一些 .NET(加载的第一个 .NET 程序集为 CLR 付费)。
- 我们希望缩短加载时间,显然我们已经进行了分析并改进了代码中的热点。
我忘记提到的是,我们通过重新设置所有二进制文件的基础来获得一些改进,这样加载器就不必在加载时执行此操作。
解决方案
您如何分析您的代码?并非所有分析方法都是相同的,有些方法比其他方法更能找到热点。您正在加载大量文件吗?如果是这样,磁盘碎片和寻道时间可能会发挥作用。
也许甚至将基本的计时信息粘贴到代码中、写入日志文件并在冷/热启动时检查文件将有助于识别 在哪里 该应用程序正在花费时间。
如果没有更多信息,我会倾向于文件系统/磁盘缓存作为两种环境之间可能的差异。如果是这种情况,那么您要么需要花更少的时间预先加载文件,要么找到更快的方法来加载文件。
例子:如果要加载大量二进制数据文件,请通过将它们组合成一个文件来加快加载速度,然后一次读取将整个文件放入内存并解析其内容。更少的磁盘寻道和从磁盘读取数据所花费的时间。再说一次,也许这并不适用。
我不知道有什么工具可以清除磁盘/文件系统缓存,但是您可以编写一个快速应用程序来从磁盘读取一堆不相关的文件,从而导致文件系统/磁盘缓存加载不同的信息。
其他提示
很难在软件中真正模拟重新启动。当您重新启动时,计算机中的所有设备都会声明其重置位,这将导致系统范围内的所有内存丢失。
在现代机器中,内存和缓存无处不在:有VM子系统,它为程序存储内存页,然后操作系统在内存中缓存文件内容,然后您就得到了硬盘驱动器本身上扇区的磁盘缓冲区。您可能可以重置操作系统缓存,但是驱动器上的磁盘缓冲区呢?我不知道有什么办法。
加速应用程序启动的一种成功方法是将 DLL 切换为延迟加载。这是一个低成本的更改(一些修改项目设置),但可以使启动速度显着加快。然后,在分析模式下运行depends.exe,找出启动期间加载的DLL,并恢复它们的延迟加载。请记住,您还可以延迟加载所需的大多数 Windows DLL。
改善应用程序冷启动时间的一个非常有效的技术是优化函数链接排序。
Visual Studio 链接器允许您传入一个文件,其中列出了正在链接的模块中的所有函数(或只是其中一些 - 不一定是全部),并且链接器会将这些函数彼此相邻地放置在记忆。
当您的应用程序启动时,通常会在整个应用程序中调用 init 函数。其中许多调用将针对尚未在内存中的页面,从而导致页面错误和磁盘寻道。这就是启动缓慢的原因。
优化您的应用程序,将所有这些功能结合在一起可能是一个巨大的胜利。
查看 Visual Studio 2005 或更高版本中的配置文件引导优化。PGO 为您做的一件事是函数链接排序。
构建过程有点困难,因为使用 PGO,您需要链接、运行应用程序,然后重新链接配置文件运行的输出。这意味着您的构建过程需要有一个运行时环境,并在错误构建后进行清理等等,但回报通常是在不更改代码的情况下冷启动速度提高 10+ 或更多。
这里有一些关于 PGO 的更多信息:
作为函数顺序列表的替代方法,只需将将在同一部分中调用的代码分组即可:
#pragma code_seg(".startUp")
//...
#pragma code_seg
#pragma data_seg(".startUp")
//...
#pragma data_seg
当代码发生变化时,它应该很容易维护,但具有与函数顺序列表相同的优点。
我不确定函数 order list 是否也可以指定全局变量,但使用这个 #pragma data_seg 就可以了。
例如,使用一种使应用程序更快(某种程度上)冷启动的方法。Adobe Reader,通过在启动时加载一些文件,从而对用户隐藏冷启动。仅当程序不应该立即启动时才可用。
另一个注意事项是,.NET 3.5SP1 据称大大提高了冷启动速度,但具体提高了多少,我不能说。
可能是NIC(LAN卡),您的应用程序取决于需要网络出现的某些其他服务。因此,单独分析您的应用程序可能无法完全告诉您这一点,但您应该检查应用程序的依赖关系。
如果您的应用程序不是很复杂,您可以将所有可执行文件复制到另一个目录,这应该类似于重新启动。(剪切和粘贴似乎不起作用,Windows足够聪明,知道移动到另一个文件夹的文件会缓存在内存中)