【问题标题】:Why does Delphi's compilation speed degrade the longer it's open, and what can I do about it?为什么Delphi打开的时间越长编译速度越慢,我该怎么办?
【发布时间】:2011-09-28 12:16:12
【问题描述】:

十多年来,我的公司一直在用 Delphi 运行一个大型项目。我们的代码库多年来一直在增长,现在大约有 400 万行代码。编译速度正在成为一个问题。我们已经花时间清除单元循环引用(编译速度慢的一个已知原因),并检查了设置的各个方面。它已经到了我们无法控制的程度。

目前,在运行 Windows XP SP3 和 Delphi 2006 的 4 核 PC 上,重新启动 Delphi 并进行完整构建,大约需要 40 秒。然后,如果我们立即在同一个 Delphi 会话中进行另一个完整构建,则需要 1m 40s。再做一个完整的构建,它会变得更糟。以此类推。

(我们很清楚Windows本身是缓存文件的,这对编译速度有很大的影响。上图是基于文件被缓存的情况。我们通过让Delphi编译一次项目来设置这样的场景,终止然后开始一个新的 Delphi 会话。因此,虽然 40 秒看起来并不慢,但这只是因为文件被 Windows 缓存了。我们这样做是为了进行苹果与苹果之间的比较。)

让我们困惑的是为什么编译速度会变差。 (我们过去观察到,如果项目有很多单元循环引用,速度会更慢。)如果我们终止 Delphi 并开始一个新会话,编译时间将回到 40 秒。我们观察到的更有趣的事情是,我们可以通过单击“取消”按钮中止编译然后立即进行完整构建来实现相同的速度“改进”。编译时间也将回到 40 秒。

在我们看来,Delphi 自己的单元依赖缓存不如从头构建它高效,而且随着时间的推移它变得越来越糟。它还显示取消按钮以某种方式清除此缓存。我们的想法是,如果我们可以利用执行此清除的 Delphi IDE 子系统,我们可以始终将编译速度保持在其峰值性能。但我们不知道怎么做。

有人知道我们能做什么吗?

我们仍在使用 Delphi 2006,因为我们还没有找到将我们的大型项目移植到 Unicode 的可行方法。我在论坛上读到,最新的 Delphi XE 在单元循环引用方面表现出类似的编译速度问题。有谁知道 Delphi XE 是否解决了这个问题?

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

【问题讨论】:

  • 您是否排除了在 IDE 中运行的杀毒软件、索引软件和第 3 方专家?
  • 你考虑过命令行编译器吗?
  • 关于单元引用的剔除,您是手动进行的吗?如果是这样,你应该试试 CnPack 的 Uses Cleaner。 (我没有遇到过问题,但在开始之前备份你的文件不会有什么坏处)
  • 请注意,“最先进的 4 核 PC”在这里并没有多大帮助。 Delphi 编译器将只使用一个内核,因此使用更快的内核会更好。即在其他条件相同的情况下,采用双 3.33 Ghz 而非四 1.8 Ghz。

标签: performance delphi compilation


【解决方案1】:

如果您构建应用程序,这里有一些技巧可以加快进程:

  • 在构建之前擦除所有 *.dcu (del *.dcu /s);
  • 在对应的硬盘上运行good defragmenter
  • 将大部分源文件放在同一个目录下,并尽量让 IDE 和 Project 库路径尽可能短,最常用的条目放在最前面;
  • 安装DelphiSpeedUp

Delphi 2007 的编译速度应该比 Delphi 2006 快。

Delphi 2009/2010/XE 可能会更慢:从用户实验来看,泛型和新 RTTI 的实现使编译过程更加复杂,发现实际实现更慢,例如与 Delphi 2007 相比。

更新:

您是否尝试启用 ProjectClearUnitCacheItem 隐藏菜单项?

我通过 CnPack 或DDevExtension 启用了此条目(我不知道是哪一个启用的,可能是后者)。这可以用来清除内部单元缓存。

【讨论】:

  • @A.Bouchez 什么是单元缓存,清除它有什么好处?
  • @David 我用过这个,例如当我破解 VCL 源代码时,对于synopse.info/forum/viewforum.php?id=6,编译器确实为 dcus 维护了一个内部缓存。对于 VCL 部分,如果您修改 VCL 源代码,则必须退出然后进入 IDE 以在下次构建时考虑修改。但这也许可以解决 OP 问题,因为它似乎是同一个 IDE 会话中的性能问题。由于它对我来说可以替代 IDE 退出/重新启动,因此对 John 来说可能是一样的。
  • 对于 OP:如果单击“Clear Unit Cache”然后“Build”再次快速构建,您可以编写一个小专家,在其中自动安装“Clear unit cache + Build”两者都有。
  • @A.Bouchez 是的!隐藏的“清除单元缓存”菜单项可以解决问题!它使编译时间回到最初的 40 秒。优秀!谢谢。 (顺便说一句,Delphi 花了 8 秒来清除单元缓存。有趣的是,任务管理器没有显示内存使用的任何变化。)
  • @John 很高兴你找到了自己的方式。因此,我不是内存或速度问题,而是缓存的内部布局在涉及很多单元时无法按预期扩展。应该在内部使用某种 O(n²) 算法(例如嵌套循环),并且无法按预期扩展。如果它仍然存在于 Delphi XE 中,也许值得创建一个 QC。 ;)
【解决方案2】:

性能逐渐下降可能是由于某种内存泄漏或编译器中的其他错误。天知道 D2005 和 D2006 受够了!如果您无法升级到支持 Unicode 的 Delphi 版本,您至少应该更新到 D2007(我相信 Embarcadero 仍然可以使用它)以获得更好的稳定性。

此外,正如 Robert Frank 在评论中提到的,请查看 Andreas Hausladen 的工具。就在几天前,他发布了一个补丁,大大提高了编译速度。不幸的是,该特定功能显然仅适用于 D2009 及更高版本,但他的许多修复有助于加快各种速度,包括编译器。

【讨论】:

  • 我怀疑是这种情况。我建议使用 SysInternals 的 Process Explorer 来查看每次编译项目时 bds.exe 的内存使用量是否增加。这将证实内存泄漏理论。
  • 听起来更像是“内存泄漏阴谋论”。如果您有足够的 RAM,IDE 需要一些时间才能开始交换到磁盘。
【解决方案3】:

Andreas Hausladen 的 DelphiSpeedUp 非常值得一试,但这只会帮助提高 IDE 性能,而不是我理解的编译。

另一个没有人建议的想法是使用高规格固态磁盘。

我建议使用具有大量 RAM 的 64 位 Windows 7 以获得最佳文件缓存性能。

感谢您的项目不是用 C++ 编写的!

【讨论】:

  • + 用于 64 位 Win7,因为 OP 提到的 4 核 Windows XP 系统不是最先进的,不是今天!但我不太确定那些高规格的固态磁盘:OP 说他正在强制 Windows 在进行实际构建之前缓存所有文件。我不确定更好的 I/O 是否会加快速度。
  • +1 表示固态磁盘。我正在运行一台我用 300G Crucial SSD 和 1TB WD HD 在 W7 64 位下构建的新机器。所有工作的 Delphi 项目都位于 SSD 上并构建在 SSD 上。第一次在 D7 和 XE 中构建 100 万行代码是 11 秒,第二次是 8 秒。 SSD 传输速率为 200-300 MB/s,而 1TB 磁盘的传输速率为 40 B/s-ish。
  • @Brian 我不认为传输速率是这里的关键因素,而是开始传输的延迟。
  • @David 我说的是 C RTL,它也被 Andreas 破解了。他不仅修补了 IDE 部分。参见例如他对可怜的不情愿的命令行编译器做了什么:andy.jgknet.de/blog/ide-tools/dcc32speed-12
  • @David Heffernan - 虽然使用固态驱动器并不能解决编译速度逐渐下降的问题(我们遇到的主要问题),但我们确实将其视为加速编译的并行解决方案(当 pas 文件不在 Windows 缓存中时)。谢谢。
【解决方案4】:

考虑在内部使用运行时包进行构建,然后在将代码发送到 QA 部门或分发您的应用程序时构建整体可执行文件。

这需要额外的维护,但构建时间的显着增加在 IMO 中是值得的。

我们有一个 2.4 MLOC 项目,其中包含大约 40-50 个较小的支持应用程序。当针对一组运行时包进行编译时,该项目构建了大约 500K 行并且构建速度提高了大约 6 倍(15 秒对 90 秒)。由于大量打包代码是共享的,因此许多较小的应用程序可以在一秒钟或更短的时间内完成编译。

您需要确保测试整体可执行文件,而不是打包的可执行文件。但一般来说,如果您遵循良好的编码习惯,您应该不会看到太多太多的行为差异。

【讨论】:

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

这个question 有更多建议以获得更好的编译速度。避免循环引用和检测未使用的单元(使用 CnWizards)效果更好。

【讨论】:

    【解决方案6】:

    您是否尝试使用脚本命令行编译代码?

    从命令行重新编译是否使进程停留在 40 秒?

    从 cmd "dcc32.exe" 运行以查看使用情况。

    更新: 我现在不能检查它,但是你应该尝试从命令行编译,看看你是否尝试从 ide 运行,ide 不应该重新编译,并让你用 debug 运行。

    【讨论】:

    • 在实践中,我发现命令行编译器至少在大多数 Delphi 版本中都比 IDE 编译器慢,除非您使用一些特定于加速的技巧,例如 andy.jgknet.de/blog/ ide-tools/dcc32speed-12
    • 我们确实使用命令行来进行生产部署的最终构建。是的,它提供了相当一致的 40 秒编译时间。但是你不会在 IDE 中失去调试吗? (我不知道我们是否有黑客攻击。我需要和我的同事核实一下。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 2023-03-26
    • 2015-12-20
    相关资源
    最近更新 更多