我有这个简单的代码:
sealed class GenObj
{
~GenObj()
{
Console.WriteLine("In Finalize method");
}
}
public static class Program
{
public static void Main()
{
Console.WriteLine("Maximum generations: " + GC.MaxGeneration);
Object o = new GenObj();
Console.WriteLine("Gen " + GC.GetGeneration(o)); // line 3
GC.Collect();
Console.WriteLine("Gen " + GC.GetGeneration(o)); // line 5
GC.Collect();
Console.WriteLine("Gen " + GC.GetGeneration(o)); // line 7
GC.Collect();
Console.WriteLine("Gen " + GC.GetGeneration(o));
}
}
输出:
Maximum generations: 2
Gen 0
Gen 1
Gen 2
Gen 2
但是有一个问题。
这本书(c#via clr)也在开头说:当CLR初始化时,它会为所有三个选择预算 代。正如我之前提到的,第0代的预算是 约为256 KB,第1代的预算约为2 MB。
...
可能有几个集合,但是中的对象 第1代仅在第1代达到其预算时进行检查, 这通常需要几代0的垃圾收集。
问题:
在第4行,我可以理解它为什么不在第1代。(在GC之后从0移到1)
我不理解的是第7行。
根据这本书:the objects in generation 1 are examined only when generation 1 reaches its budget
我认为它已经达到预算。所以我想它应该留在第一代!!!
根据这本书 - 它不应该转移到第二代。
我缺少什么?
P.S。这里是link,其中有书中的精确文本(相信我,我有PDF)
答案 0 :(得分:2)
在向该书的作者发送电子邮件之后
这是他的回答
预算用于告诉GC哪些代IT应该 搜集。如果您自己调用GC.Collect,那么您正在告诉GC 忽略预算,只做一个集合。你逼迫了 早期收集,促进老一代的对象。
答案 1 :(得分:1)
我相信Damien是对的。本书描述了当您不强制完全垃圾收集时会发生什么。但你这样做。所以,正确的文字可以是这样的:
可能有多个集合,但只有在第1代GC发生时才会检查第1代中的对象。第1代GC发生在第1代达到预算时,通常需要第0代的几个垃圾收集,但您也可以通过调用
GC.Collect(1)
来强制它。
答案 2 :(得分:1)
不要相信你在书中读到的所有内容。
当作者写这本书时,他/她可能不完全理解这个主题。 在作者写完这本书之后,实施可能已经改变了。
以下是我的理解:
初始GC预算由gc模式和机器配置决定。
小对象在gen0区域中分配,移动到gen1区域,然后通常移动到gen2区域。 大对象分配在大对象堆中,这被认为是gen2。
答案 3 :(得分:0)
以下是测试GC预算的方法:
const int AllocSize = 64; // 64 kb block
const int MaxBudget = 5 * 1024; // Test max to 5 mb
static int GetG0Budget()
{
GC.Collect(0, GCCollectionMode.Forced, true);
int gcCount = GC.CollectionCount(0);
int sum = 0;
for (int i = 0; i < MaxBudget; i += AllocSize)
{
byte[] buffer = new byte[AllocSize * 1024];
sum += buffer[0];
if (GC.CollectionCount(0) != gcCount)
{
return i;
}
}
return MaxBudget + sum;
}
在不同的机器上尝试,将返回不同的值。例如,在功能强大的台式机,笔记本电脑和Windows手机上试用它。