【问题标题】:Which generation static readonly member will be allocated in将在哪一代静态只读成员中分配
【发布时间】:2017-12-21 15:15:58
【问题描述】:

有这个代码

class Program
    {
        private static readonly int[] s_numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        static void Main(string[] args)
        {
            foreach (int number in s_numbers)
            {
                WriteLine(number);
            }

            WriteLine("Press ENTER to close the app.");
            ReadLine();
        }
    }

我想知道s_numbers 数组将被分配到哪里(哪一代)? 我的推理如下 - 因为这是static readonly 成员,所以它不会是nulled,所以在AppDomain 的生命周期内不会是GC'd。因此,直接将其放入 GEN2(如大型对象)而不在 GEN0 中分配它然后将其从 GEN0 移动到 GEN2 是有意义的。 不幸的是,我无法确认是否是这种情况(我无法使用 WinDbg 找到这个数组)。

所以重申一下这个问题 - 这个static readonly 成员将被分配到哪一代 GC 中?

【问题讨论】:

  • 只用了一次,优化者可能不这么认为。
  • 由于在普通托管堆中分配内存的唯一方法是增加 GEN0 中的高水位标记,您如何建议您的“优化”直接进入 GEN2?
  • @Rob 所以在这种情况下它是 GEN0,如果它会被其他地方使用(通过公共只读属性)怎么办?
  • @Damien_The_Unbeliever 那么它是如何处理大型物体的呢?还是说大对象也先在 GEN0 中分配,最终通过 GC 提升到 GEN2 ?
  • 不,大对象有一个专用的堆 (LOH)

标签: c# .net


【解决方案1】:

readonly 是个谎言。您认为readonly 主要只是一个指南,而不是实际规则- 至少在大多数运行时:

private static void ThisWorksFine()
{
    typeof(Program).GetField("s_numbers", BindingFlags.NonPublic | BindingFlags.Static)
        .SetValue(null, null);
}

目前不存在任何优化来检查这种“分配给只读静态字段”场景并在 GEN2 中分配数组。可以吗?也许。我敢打赌,对于非常有限数量的分配/对象来说,复杂性是不值得的。它今天不存在,所以它遵循通常的分配/促销规则。

【讨论】:

    【解决方案2】:

    Part of Adriaan Stander‘s answer

    来自Understanding garbage collection in .Net

    第一次创建对象时,将其放入第 0 代。当第 0 代填满时,将调用垃圾收集器。在第一代垃圾收集中幸存下来的对象被提升到下一个更高的一代,第一代。在第一代垃圾收集中幸存的对象被提升到下一个最高一代,第二代。这个算法对垃圾有效地工作对象的集合,因为它很快。请注意,第 2 代是垃圾收集器支持的最高代

    所以它不会立即从 GEN2 开始,而是会转到 GEN0->GEN1->GEN2。

    【讨论】:

    • 感谢您的回答。问题不在于 GC 通常是如何工作的,而是关于 static readonly 成员是否有任何优化。
    • @Michael:只是出于兴趣,你为什么想知道呢?你实现了自己的垃圾收集器吗?
    • 他要么只是好奇,要么可能想成为一个更好的程序员,编写运行时和内存高效的代码。
    • @TimSchmelter 非常好的问题。想象一下,您有一个被频繁调用的方法,并且在该方法中您初始化了静态数组(那里的数据是静态的)。一旦你完成了方法调用,它就不需要了,所以它可以是 GCd。我在想如果将这个数组设置为static readonly 将是一个很好的优化,不会对 GC 和工作内存集施加太大压力。
    • @Toxantron:如果你想成为一个更好的程序员,你不应该针对垃圾收集器的实现细节优化你的代码,这些细节明天可能会改变。您应该优化代码的可读性,它应该可以工作。如果该数组占用了您的内存,请考虑使用数据库。
    猜你喜欢
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    • 2014-05-09
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多