13

与已经打开一次(热启动)相比,我们的应用程序在重新启动(冷启动)后启动所需的时间要长得多。

大多数(如果不是全部)差异似乎来自加载 DLL,当 DLL 位于缓存的内存页面中时,它们的加载速度要快得多。我们尝试使用ClearMem来模拟重新启动(因为它比实际重新启动花费的时间要少得多)并且得到了好坏参半的结果,在某些机器上它似乎非常一致地模拟了重新启动,而在某些机器上则不是。

总结一下我的问题是:

  1. 您是否经历过冷启动和热启动之间的启动时间差异?
  2. 你是如何处理这些差异的?
  3. 你知道一种可靠地模拟重启的方法吗?

编辑:

澄清评论:

  • 该应用程序主要是带有一些 .NET 的本机 C++(加载的第一个 .NET 程序集为 CLR 付费)。
  • 我们正在寻求改善加载时间,显然我们做了我们的分析并改进了代码中的热点。

我忘了提到的是,我们通过重新构建所有二进制文件得到了一些改进,因此加载程序不必在加载时执行此操作。

4

10 回答 10

6

至于模拟重启,您是否考虑过从虚拟 PC运行您的应用程序?使用虚拟化,您可以方便地一遍又一遍地复制一组条件。

我还会考虑使用某种类型的分析应用程序来发现导致时间延迟的代码位,然后判断该代码中有多少是真正需要的,或者是否可以以不同的方式实现。

于 2008-09-24T13:12:47.700 回答
4

很难在软件中真正模拟重启。当您重新启动时,您机器中的所有设备的重置位都会被置位,这应该会导致系统范围内的所有内存丢失。

在现代机器中,内存和缓存无处不在:VM 子系统为程序存储内存页面,然后操作系统在内存中缓存文件的内容,然后您就可以-硬盘驱动器本身扇区的磁盘缓冲区。您可能可以重置操作系统缓存,但是驱动器上的磁盘缓冲区?我不知道有什么办法。

于 2008-09-24T13:15:06.850 回答
3

你是如何分析你的代码的?并非所有分析方法都是平等的,有些方法比其他方法更好地发现热点。您是否正在加载大量文件?如果是这样,磁盘碎片和寻道时间可能会起作用。

甚至可能将基本的时间信息粘贴到代码中,写入日志文件并在冷/热启动时检查文件将有助于确定应用程序在哪里花费时间。

如果没有更多信息,我会倾向于文件系统/磁盘缓存作为这两种环境之间的可能差异。如果是这种情况,那么您要么需要花更少的时间预先加载文件,要么找到更快的方法来加载文件。

示例:如果您要加载大量二进制数据文件,则通过将它们组合成一个文件来加快加载速度,然后一次读取整个文件到内存中并解析它们的内容。更少的磁盘寻道和读取磁盘的时间。同样,也许这不适用。

我不知道任何清除磁盘/文件系统缓存的工具,但是您可以编写一个快速应用程序来从磁盘读取一堆不相关的文件,从而导致文件系统/磁盘缓存加载不同的信息。

于 2008-09-24T18:53:32.123 回答
2

@Morten Christiansen说:

例如,Adobe reader 使用了一种使应用程序更快地启动冷启动(有点)的方法,通过在启动时加载一些文件,从而对用户隐藏冷启动。这仅在程序不应该立即启动时才可用。

这使得客户在每次启动时为初始化我们的应用程序付费,即使它没有被使用,我真的不喜欢这个选项(Raymond也不喜欢)。

于 2008-09-25T07:27:45.460 回答
2

加速应用程序启动的一种成功方法是将 DLL 切换为延迟加载。这是一个低成本的改变(一些对项目设置的摆弄),但可以使启动速度显着加快。然后,在分析模式下运行depends.exe,以确定在启动期间加载了哪些DLL,并恢复它们的延迟加载。请记住,您还可以延迟加载所需的大多数 Windows DLL。

于 2008-09-25T10:53:04.140 回答
2

改善应用程序冷启动时间的一个非常有效的技术是优化函数链接排序。

Visual Studio 链接器允许您传入一个文件,其中列出了正在链接的模块中的所有函数(或只是其中的一些 - 不必是所有函数),并且链接器会将这些函数彼此相邻放置记忆。

当您的应用程序启动时,通常会在整个应用程序中调用 init 函数。其中许多调用将针对尚未在内存中的页面,从而导致页面错误和磁盘寻道。这就是慢启动的来源。

优化您的应用程序以使所有这些功能结合在一起可能是一个巨大的胜利。

查看 Visual Studio 2005 或更高版本中的配置文件引导优化。PGO 为您做的一件事是函数链接排序。

在构建过程中工作有点困难,因为使用 PGO,您需要链接、运行您的应用程序,然后与配置文件运行的输出重新链接。这意味着您的构建过程需要有一个运行时环境并在错误构建之后进行清理等等,但回报通常是 10+ 或更多更快的冷启动,无需更改代码。

这里有更多关于 PGO 的信息:

http://msdn.microsoft.com/en-us/library/e7k32f4k.aspx

于 2008-12-18T20:11:56.980 回答
1

作为函数顺序列表的替代方法,只需对将在相同部分中调用的代码进行分组:

#pragma code_seg(".startUp")
 //...
#pragma code_seg

#pragma data_seg(".startUp")
 //...
#pragma data_seg

随着代码的更改,它应该易于维护,但与函数顺序列表具有相同的好处。

我不确定函数顺序列表是否也可以指定全局变量,但使用这个#pragma data_seg 就可以了。

于 2009-03-17T11:38:57.920 回答
0

例如,Adobe reader 使用了一种使应用程序更快地启动冷启动(有点)的方法,通过在启动时加载一些文件,从而对用户隐藏冷启动。这仅在程序不应该立即启动时才可用。

另一个注意事项是,.NET 3.5SP1 据说已经大大提高了冷启动速度,但我不能说多少。

于 2008-09-24T14:08:35.613 回答
0

它可能是 NIC(LAN 卡),并且您的应用程序依赖于需要网络启动的某些其他服务。因此,单独分析您的应用程序可能无法完全告诉您这一点,但您应该检查应用程序的依赖关系。

于 2008-09-24T18:56:29.760 回答
-1

如果您的应用程序不是很复杂,您可以将所有可执行文件复制到另一个目录,它应该类似于重新启动。(剪切和粘贴似乎不起作用,Windows 足够聪明,可以知道移动到另一个文件夹的文件缓存在内存中)

于 2009-03-18T11:25:34.877 回答