为什么Delphi打开时间越长,编译速度就越慢?有什么解决办法吗?

37

我公司已经使用Delphi开发大型项目十多年了。这些年我们的代码库不断增长,现在已达到约400万行代码。编译速度成为一个问题。我们花费了很多时间清除单元循环引用(缓慢编译的已知原因),并检查了设置的每个方面。但是我们发现,我们无法通过我们能控制的任何方式在实质上进一步改善。

目前,在一个拥有4核心、运行Windows XP SP3和Delphi 2006的最新PC上,如果我们从头开始启动Delphi并进行完整的构建,则需要大约40秒钟。然后,如果我们立即在同一个Delphi会话中再次进行完整的构建,它将需要1分40秒。再进行完整构建,情况会变得更糟。如此反复。

(我们非常清楚Windows本身会缓存文件,并且这对编译速度有很大影响。以上数据是基于文件已被缓存的情况。我们通过让Delphi编译一次项目,终止它,然后启动新的Delphi会话来设置这种情况。因此,虽然40秒看起来并不慢,但只是因为Windows缓存了文件。我们这样做是为了进行苹果对苹果的比较。)

令我们困惑的是为什么编译速度会变慢。(我们曾经观察到,如果项目存在很多单元循环引用,则减速会更加严重。)如果我们终止Delphi并启动新会话,则编译时间将恢复到40秒。更有趣的是,我们发现只要通过单击“取消”按钮来中止编译,然后立即进行完整构建,编译时间也会恢复到40秒。

对我们来说,Delphi自己缓存单元依赖关系的效率似乎不如从头开始构建,并且随着时间的推移而变得越来越糟糕。同时,似乎“取消”按钮可以清除这个缓存。我们考虑的是,如果我们能够利用Delphi IDE子系统进行清除,我们就可以始终保持编译速度处于最佳状态。但是我们不知道该怎么做。

有人知道我们该怎么办吗?

我们仍在使用Delphi 2006,因为我们还没有找到将大型项目迁移到Unicode的可行方法。我在论坛上看到最新的Delphi XE存在与单元循环引用相关的编译速度问题。有人知道Delphi XE是否解决了这个问题吗?

p.s. 我们也知道将项目拆分为运行时包可以减少编译时间。但由于部署和管理原因,我们尽量避免使用运行时包。


3
你是否排除了反病毒软件、索引软件和在集成开发环境中运行的第三方专家? - Cosmin Prund
8
你考虑过命令行编译器吗? - J-16 SDiZ
8
http://andy.jgknet.de/blog/ide-tools/delphispeedup/ - RobertFrank
1
关于单位引用的清理,您是手动完成的吗?如果是的话,您应该尝试一下 CnPack 的 Uses Cleaner。(我没有遇到过问题,但在开始之前备份文件不会有坏处) - Lieven Keersmaekers
3
请注意,“带有4个内核的最先进PC”在这里并没有太大的帮助。Delphi编译器只会使用一个内核,因此您最好选择更快的内核。也就是说,其他条件相同的情况下,应该选择双3.33 GHz而不是四核1.8 GHz。 - Chris Thornton
显示剩余8条评论
6个回答

23

如果您要构建应用程序,以下是一些加速该过程的技巧:

  • 在构建之前清除所有*.dcu文件(del *.dcu /s);
  • 在相应的硬盘上运行一个好的碎片整理软件
  • 将大部分源文件放在同一个目录中,并尽量缩短IDE和项目库路径,最常用的条目放在最前面;
  • 安装DelphiSpeedUp

Delphi 2007应该比Delphi 2006编译得更快。

根据用户实验,Delphi 2009/2010/XE可能会更慢:泛型和新RTTI的实现使编译过程更加复杂,实际实现也被发现比Delphi 2007更慢。

更新:

您尝试启用了隐藏菜单项ProjectClearUnitCacheItem吗?

Clear Unit Cache entry

我已经启用了这个选项,不知道是CnPack还是DDevExtension(可能是后者)。这可以用于清除内部单元缓存。


1
@A.Bouchez 什么是单元缓存,清除它有什么好处? - David Heffernan
@David 我在破解 VCL 源代码的时候使用了这个技巧,网址是 http://synopse.info/forum/viewforum.php?id=6。编译器会为 dcu 文件维护一个内部缓存。对于 VCL 部分,如果你修改了 VCL 源代码,在下一次构建之前,你需要退出并重新进入 IDE 才能让修改生效。但这可能可以解决 OP 的问题,因为它似乎是同一 IDE 会话中的性能问题。既然这个方法替代了 IDE 退出/重启,那么 John 也可以尝试一下。 - Arnaud Bouchez
针对OP:如果单击“清除单元缓存”然后再单击“构建”可以使构建速度变快,那么您可以编写一个小专家来安装“清除单元缓存+构建”,它会自动执行这两个操作。 - Cosmin Prund
5
@A.Bouchez 没错!隐藏的“清除单元缓存”菜单项可以解决问题!它将编译时间恢复到最初的40秒。太棒了!谢谢。(顺便说一下,Delphi花费了8秒钟来清除单位缓存。有趣的是,任务管理器没有显示内存使用量的任何变化。) - John
@John 很高兴你找到了解决方法。问题并不是内存或速度问题,而是缓存的内部布局在涉及大量单元时无法按预期扩展。某种O(n²)算法(例如嵌套循环)应该在内部使用,但无法按预期扩展。如果在Delphi XE中仍然存在这个问题,那么可能值得创建一个QC。 ;) - Arnaud Bouchez

18

渐进的性能下降可能是由于编译器中的某种内存泄漏或其他错误导致的。天知道 D2005 和 D2006 已经有足够多的这些问题了!如果您无法升级到支持Unicode的Delphi版本,那么您至少应该升级到D2007(我认为Embarcadero仍然提供)以获得更好的稳定性。

此外,正如Robert Frank在评论中提到的那样,请查看Andreas Hausladen的工具。就在几天前,他发布了一个补丁,可以显著提高编译速度。不幸的是,那个具体的功能似乎只适用于D2009及更高版本,但他的很多修复都有助于加快各种操作的速度,包括编译器。


我怀疑这是问题所在。我建议使用SysInternals的Process Explorer来查看每次编译项目时bds.exe的内存使用情况是否增加。这将证实内存泄漏理论。 - Chris Thornton
听起来更像是“内存泄漏阴谋论”。如果你有足够的RAM,IDE开始开始交换到磁盘之前需要一些时间。 - Arnaud Bouchez

7

建议尝试使用Andreas Hausladen的DelphiSpeedUp,它可以提高IDE的性能,但据我所知只能影响编译。

另一个还没有人提出的想法是使用高配置固态硬盘。

我推荐使用64位Windows 7并搭配大量内存以获得最佳文件缓存性能。

庆幸你的项目不是用C++写的!


1
对于64位Win7来说,因为像OP提到的4核Windows XP系统已经不再是现代化的了,所以这是一个好选择!但是我对那些高规格的固态硬盘并不确定:OP说他正在强制Windows在实际构建之前缓存所有文件。我不确定更好的I/O是否会加速事情。 - Cosmin Prund
2
+1 给固态硬盘。我正在运行一台新机器,它由300G Crucial SSD和1TB WD HD在W7 64位下构建而成。所有工作中的Delphi项目都位于SSD上进行构建。100万行代码在D7和XE中第一次构建需要11秒,在第二次构建时只需8秒。SSD传输速率为200-300 MB/s,而1TB硬盘的速率仅为40 B/s左右。 - Brian Frost
3
我认为这里关键因素不是传输速率,而是开始传输的延迟。 - David Heffernan
2
@David,我是指C RTL,这也被Andreas攻破了。他不仅修补了IDE部分。看看他对可怜的、不情愿的命令行编译器做了什么:http://andy.jgknet.de/blog/ide-tools/dcc32speed-12 - Arnaud Bouchez
1
@David Heffernan - 虽然使用固态硬盘不能解决编译速度逐渐降低的问题(这是我们主要面临的问题),但我们认为它是加速编译的并行解决方案之一(当pas文件不在Windows缓存中时)。谢谢。 - John
显示剩余3条评论

1
考虑在内部构建运行时程序包,然后在将代码发送到QA部门或分发您的应用程序时构建单片执行文件。
这需要额外的维护工作,但是我认为编译时间的显著增加是值得的。
我们有一个240万行代码的项目,其中包括约40-50个较小的支持性应用程序。当针对一组运行时程序包进行编译时,项目的构建量约为500K行,并且构建速度快了约6倍(15秒 vs. 90秒)。由于许多打包代码是共享的,因此许多较小的应用程序编译时间仅需1秒钟或更短。
您需要确保测试单体可执行文件,而不是打包的可执行文件。但是,如果您遵循良好的编码实践,通常不应该看到太多行为差异。

我们已经考虑了你提出的建议。但我们仍然不确定引入的开销和风险是否超过了收益。 - John
这很容易理解,我同意。维护双重编译特别困难。构建配置有很大帮助。还有一个潜在的好处我之前没有提到:因为包不能递归地相互依赖,打包构建可以强制实施良好的软件分层。例如,低级代码不能静态链接到高级代码。这就是至少将代码组织成运行时包的原因。 - David Robb

0
你尝试使用脚本命令行编译代码了吗?
从命令行重新编译是否使进程停留在40秒?
从cmd运行"dcc32.exe"以查看用法。
更新: 我现在无法检查,但是你应该尝试从命令行编译并查看是否尝试从ide运行,ide不应重新编译,并允许您进行调试。

我在实践中发现,在大多数Delphi版本中,命令行编译器速度慢于IDE编译器,除非您使用一些特定的加速hack(例如 andy.jgknet.de/blog/ide-tools/dcc32speed-12)。 - Arnaud Bouchez
1
我们确实使用命令行进行生产部署的最终构建。是的,它提供了相当一致的40秒编译时间。但是你不会失去IDE中的调试功能吗?(我不知道我们是否已经有了相关的解决方案。我需要与我的同事核实一下。) - John

0

这个问题提供了一些更好的编译速度建议。避免循环引用和检测未使用的单元(使用CnWizards)效果更佳。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接