【问题标题】:How garbage collection decides generation for variable垃圾收集如何决定变量的生成
【发布时间】:2017-05-22 04:09:55
【问题描述】:

我知道 GC 有 3 (0, 1, 2) 代,但我想知道 GC 如何决定变量的代?

我认为所有变量都进入第 0 代,并在一段时间后移动到第 1 代和第 2 代。GC 决定代的大小是否重要?

程序1:

private static void Main(string[] args)
{
        int a = 0;
        string name = "Test";
        var byteArray = new byte[10];
        byteArray[4] = 4;

        Console.WriteLine($"Generation of array {GC.GetGeneration(byteArray)}");
        Console.WriteLine($"Generation of local int variable {GC.GetGeneration(a)}");
        Console.WriteLine($"Generation of local string variable {GC.GetGeneration(name)}");
}

结果

Generation of array 0
Generation of local int variable 0
Generation of local string variable 0

程序2:

private static void Main(string[] args)
{
        int a = 0;
        string name = "Test";
        var byteArray = new byte[100000000];
        byteArray[4] = 4;

        Console.WriteLine($"Generation of array {GC.GetGeneration(byteArray)}");
        Console.WriteLine($"Generation of local int variable {GC.GetGeneration(a)}");
        Console.WriteLine($"Generation of local string variable {GC.GetGeneration(name)}");

}

结果

Generation of array 2
Generation of local int variable 0
Generation of local string variable 0

【问题讨论】:

  • 您理解正确。对象从第 0 代开始,然后随着时间的流逝而迁移到老一代。非常大的物体是个例外——它们直接传给老一代,因为这样的巨大物体不太可能是短暂的。

标签: c# memory-management garbage-collection


【解决方案1】:

我想知道 GC 是如何决定一个变量的生成的?

变量一开始就没有被 GC 处理。 引用类型的对象是 GC'd。这些对象包含变量,但被收集的是对象

我认为所有变量都进入第 0 代,一段时间后转移到第 1 代和第 2 代。

没有。不要从变量的角度思考。从对象的角度思考。一个新分配的对象进入 gen0。如果该对象在集合中幸存下来,则将其移至 gen1。如果它在另一个集合中幸存下来,它会移动到 gen2。

现在您知道为什么在包含 int 的局部变量上调用 GetGeneration 将始终返回零。这并不是因为本地与 gen0 有某种神奇的联系。 local 不是引用类型的对象,也不是它的值!

当你将 int 传递给GetGeneration 时,int 被装箱到一个对象中;该对象是新分配的,因此它位于第 0 代。这不会告诉您有关 变量 的任何信息。如果您将 any(非 null)值类型传递给触发分配的 GetGeneration,显然该分配是 gen0。

再次,您的问题表明您认为 GC 正在查看 变量 的生命周期。 不是。它正在查看引用类型的对象的生命周期。

GC 决定生成的大小是否重要?

是的。例如,非常大的数组是从一个特殊的“大对象堆”中分配的。 “非常大”是指基本上任何大约 85KB 或更大的对象。大型对象堆 (1) 未压缩,并且 (2) 仅在常规堆进行 gen2 收集时才收集。

【讨论】:

    【解决方案2】:

    第 0 代和第 1 代需要很小,以便可以快速收集。为了保持它们的小,非常大的对象直接在第 2 代中分配。

    【讨论】:

    • 这不准确,但很接近。小对象堆gen2和大对象堆是不同的堆;它们只是同时收集的。 GetGeneration 将为大对象返回 2,但这并不意味着它们与小对象在同一个堆上。
    • 问题是对象何时进入 Gen1。见下面的结果:@E var byteArray = new byte[84987]; //获取第 0 代 var byteArray = new byte[84988]; //获取第2代
    • 第 0 代对象在第 0 代集合中存活时会进入第 1 代。
    猜你喜欢
    • 2016-04-03
    • 1970-01-01
    • 2021-03-25
    • 1970-01-01
    • 2011-05-07
    • 1970-01-01
    • 1970-01-01
    • 2019-02-22
    • 1970-01-01
    相关资源
    最近更新 更多