解释F#垃圾收集报告

时间:2012-09-16 23:39:03

标签: memory-management f# garbage-collection

我有一个相当复杂的F#应用程序,我使用F#脚本使用#time指令检查其性能。我的想法是在更改代码后运行脚本以跟踪性能并避免引入速度或内存问题。

我得到的报告是这样的:

Real: 00:00:02.908, CPU: 00:00:02.948, GC gen0: 237, gen1: 3, gen2: 1

但是在最后一次改变之后我得到了这个:

Real: 00:00:03.058, CPU: 00:00:03.057, GC gen0: 262, gen1: 262, gen2: 0

我无法弄清楚发生了什么。

更多第1代垃圾收集意味着(?)有更多长寿命对象在第0代垃圾收集中存活 - 但为什么突然从3跳到262?为什么第0代和第1代的垃圾收集数量相同?如果由于某种原因在代码更改后有更多长寿命的对象,我会期望这样的东西:

Real: 00:00:02.908, CPU: 00:00:02.948, GC gen0: 212, gen1: 54, gen2: 1

即。垃圾收集对象的总数相似但在第1代有更多。

或者我完全误解了这些数字(我在文档中找不到描述)?

更新

正如评论中指出的那样,我完全误解了数字:它们是每一代执行的垃圾收集的数量,而不是对象的数量。

话虽如此,我更加困惑:似乎我的应用程序将内存置于这样一种状态,即每一代0垃圾收集也会触发第一代,我无法想象这个状态会是什么。我尝试了各种测试程序来复制这种行为而没有运气。

我仍然需要按照评论和pad的回答中的建议尝试分析器。

更新2

我按照评论中的建议尝试了CLR探查器 - 为此,我将我的F#脚本转换为程序并从探查器运行它。

我得到的报告与#time一个 - 垃圾收集完全不同:

  • 代0:279
  • 第1代:5
  • 第2代:2。

Mistery - 使用FSI.exe与独立程序相比的副作用? #time中的错误?

1 个答案:

答案 0 :(得分:2)

.NET GC是一款三代GC。正如约翰帕尔默指出的那样,这几代人的最后三个数字是the number of collections rungen1gen2中的较大数字通常表示性能不佳,因为GC必须在每个垃圾收集过程中反复标记这些未使用的对象。有关.NET GC的更深入介绍,请查看this nice article

以下是一些建议:

  1. 确保两次测量之间的“重置会话”,以便第一次会话中未使用的对象不会对第二次测量产生影响。
  2. 找到三个更大的输入来衡量。虽然这两个报告中的执行时间相似,但我希望第一种方法更具可扩展性。如果您有多种输入尺寸来测试可扩展性,那就太棒了。
  3. 测量几次以记录模式,因为您可能只是观察异常会话。
  4. 如有疑问,请在Visual Studio中执行full-range profiling。他们的报告对于绩效预测更为全面和可靠。