c# - GC Eager 根收集

标签 c# .net garbage-collection

在 Pro .NET Performance - Optimize Your C# Applications 的第 96 页上,它谈到了 GC 急切根收集:

For each local variable, the JIT embeds into a table the addresses of the earliest and latest instruction pointers where the variable is still relevant as a root. The GC then uses these tables when it performs its stack walk.



然后它提供了这个例子:
    static void Main(string[] args)
    {
        Widget a = new Widget();
        a.Use();
        //...additional code
        Widget b = new Widget();
        b.Use();
        //...additional code
        Foo(); //static method
    }

然后它说:

The above discussion implies that breaking your code into smaller methods and using fewer local variables is not just a good design measure or a software engineering technique. With the .NET GC, it can provide a performance benefit as well because you have fewer local roots! It means less work for the JIT when compiling the method, less space to be occupied by the root IP tables, and less work for the GC when performing its stack walk.



我不明白将代码分解成更小的方法会有什么帮助。
我已将代码分解为:
    static void Main(string[] args)
    {
        UseWidgetA();
        //...additional code
        UseWidgetB();
        //...additional code
        Foo(); //static method
    }

    static void UseWidgetA()
    {
        Widget a = new Widget();
        a.Use();
    }

    static void UseWidgetB()
    {
        Widget b = new Widget();
        b.Use();
    }
}

较少的本地根:

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

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

当然,这会让事情变得更糟,因为 2 个额外的方法需要 2 个额外的表。 JIT 还需要记录最早和最新的指令指针,其中变量在每个方法中仍然相关,但它只是有更多的方法来做到这一点。

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

在堆栈遍历期间,拥有更多更小的方法如何意味着更少的 GC 工作?

最佳答案

我不在萨沙的脑海里,但让我把我的两分钱花在那个上面。

首先,我认为这是一个通用规则——当你将一个方法拆分成更小的方法时,有可能某些部分不需要 JITted,因为某些子程序是有条件地执行的。

其次,JITting 确实产生了关于实时堆栈根的所谓 GC 信息。更大的方法,更大的 GC 信息理论上,在 GC 期间解释它也应该有更大的成本,但是,这可以通过将 GC 信息拆分成块来克服。但是,有关堆栈根活跃度的信息仅存储在所谓的安全点中。有两种类型的方法:

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

  • 正如运行时之书所说:“JIT 选择是完全发射还是部分发射
    基于启发式的可中断代码,以找到代码质量之间的最佳权衡,
    GC 信息的大小和 GC 暂停延迟。”

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

    关于c# - GC Eager 根收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59372255/

    相关文章:

    .net - 将代码保留在 View code 后面是不是很糟糕?

    .net - 在进程关闭期间处理 ObjectDisposedException 和类似异常?

    garbage-collection - JVM PrintGCApplicationConcurrentTime 和 PrintGCApplicationStoppedTime 标志

    c# - 关于垃圾收集 C# .NET 的问题

    c# - 如何在时间流逝时收集按键?

    c# - Http Post 正在发送带有空正文的请求

    c# - 自定义 DataGridView 重复列

    java - 在Java中重用对象的存储意味着什么?

    c# - 有效地从视频中抓取像素

    c# - 按最小值对列表列表进行排序