GC渴望根收集

时间:2019-12-17 10:29:55

标签: c# .net garbage-collection

Pro .NET性能的第96页-优化您的C#应用​​程序中,它讨论了GC急切的根集合:

  

对于每个局部变量,JIT会将表中的地址嵌入   最早和最新的指令指针,其中变量是   仍然是根源。然后,GC将使用这些表   执行它的堆栈遍历。

然后提供此示例:

posix/cpu,posix/mem

然后说:

  

以上讨论意味着将您的代码分解为更小的代码   方法和使用较少的局部变量不仅仅是一个好的设计   测量或软件工程技术。使用.NET GC,它可以   同时也提供性能优势,因为本地数量较少   根!这意味着在编译方法时,JIT的工作量减少了,   根IP表要占用的空间,并且GC的工作量减少   在执行堆栈遍历时。

我不明白将代码分解为较小的方法将有什么帮助。 我将代码分解为:

    static void Main(string[] args)
    {
        Widget a = new Widget();
        a.Use();
        //...additional code
        Widget b = new Widget();
        b.Use();
        //...additional code
        Foo(); //static method
    }

更少的本地根:

为什么本地根较少? 仍然有相同数量的本地根,每种方法中只有一个本地根。

编译方法时,JIT的工作量较少:

这肯定会使情况更糟,因为这2个额外方法需要2个额外表。 JIT仍需要记录最早和最新的指令指针,其中变量在每种方法中仍是相关的,但是它只会有更多的方法可以做到这一点。

执行GC堆栈遍历时,GC工作量减少:

采用更多较小的方法如何在堆栈遍历期间减少GC的工作量?

1 个答案:

答案 0 :(得分:3)

我不在Sasha的脑海里,但让我为此付两分钱。

首先,我将其理解为通用规则-将方法拆分为较小的方法时,有可能不需要将某些部分进行JIT处理,因为某些子例程是有条件执行的。

其次,JITting确实生成了有关活动堆栈根的所谓的 GC信息。从理论上讲,越大的方法越大的 GC info 从理论上讲,在GC期间解释它的成本也应该更高,但是,可以通过将GC Info分成多个块来解决。但是,仅针对所谓的安全点存储有关堆栈根活动度的信息。方法有两种:

  • 部分可中断-唯一的安全点是在调用其他方法期间。这样一来,方法的“可暂停性”就降低了,因为运行时需要等待这样的安全点来挂起方法,但是消耗的内存却更少了。
  • 完全可中断-方法的每条指令都被视为安全点,这显然使方法非常“可悬浮”,但需要大量存储(数量与代码本身相似)

正如《运行时手册》所说:“ JIT选择是完全发射还是部分发射 基于启发式的可中断代码,以在代码质量, GC信息的大小以及GC暂停延迟。”

我认为,较小的方法可以帮助JIT做出更好的决策(基于其启发式方法),以使方法部分或完全可中断。