我有一个相当复杂的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
一个 - 垃圾收集完全不同:
Mistery - 使用FSI.exe与独立程序相比的副作用? #time
中的错误?
答案 0 :(得分:2)
.NET GC是一款三代GC。正如约翰帕尔默指出的那样,这几代人的最后三个数字是the number of collections run。 gen1
和gen2
中的较大数字通常表示性能不佳,因为GC必须在每个垃圾收集过程中反复标记这些未使用的对象。有关.NET GC的更深入介绍,请查看this nice article。
以下是一些建议: