复活后的GC代数是多少?

6
假设一个对象有一个Finalize()方法。
当它被创建时,一个指针被添加到终结队列中。
该对象没有引用。
当进行垃圾回收时,它将引用从终结队列移动到f-reachable队列,并启动一个线程来运行Finalize方法(在其他对象的Finalize方法之后顺序执行)。
因此,对象现在(复活后)只有一个根,即来自f-reachable队列的指针。
此时,该对象是否已晋升到下一代?
2个回答

3

这是一个你可以尝试的东西。在没有调试器附加的情况下,在发布版本中运行此代码:

using System;

class Program {
    static void Main(string[] args) {
        var obj = new Foo();
        // There are 3 generations, could have used GC.MaxGeneration
        for (int ix = 0; ix < 3; ++ix) {
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
        Console.ReadLine();
    }
}

class Foo {
    int attempt = 0;
    ~Foo() {
        // Don't try to do this over and over again, rough at program exit
        if (attempt++ < 3) {
            GC.ReRegisterForFinalize(this);
            Console.WriteLine(GC.GetGeneration(this));
        }
    }
}

输出:

1
2
2

因此,它保留在由集合移动到的生成中,在每个集合上移动到下一个生成,直到达到最后一个生成。一般来说这是有意义的。


为什么没有连接调试器(只是好奇)? - Royi Namir
1
因此,调试器不会导致Jitter将* obj 变量的生命周期延长到方法的末尾。这将防止GC.Collect收集 obj *。 - Hans Passant
1
这超出了我的水平。如果在代码中添加一些注释,例如为什么要计算尝试次数以及为什么要循环三次等,那会对我有所帮助。 - Johan Larsson
1
@JohanLarsson 三次是为了展示生成链的进度。它也可以是3+....关于尝试是因为:如果他不计算尝试次数-它将永远存在。因为他总是重新注册终结器。 - Royi Namir
1
有3个GC代。 "attempts"变量是为了防止终结器线程在程序退出时尝试终结对象并且失败而疯狂。只需尝试并查看删除它时会发生什么,这就是我发布此代码的原因。看它尝试是很有趣的。现在您还可以看到程序退出时应用的2秒超时。 - Hans Passant

1

看起来答案是肯定的,这将会发生。http://msdn.microsoft.com/en-us/magazine/bb985010.aspx说:

... 两个GC(垃圾回收器)需要回收需要终结的对象所使用的内存。实际上,可能需要更多的集合,因为对象可能会晋升到较旧的代


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接