以下是关于GC的一篇很棒的文章可能会在意外的代码执行点发生:
终身,GC.KeepAlive,处理回收 - 来自cbrumme http://blogs.msdn.com/b/cbrumme/archive/2003/04/19/51365.aspx?wa=wsignin1.0
我的问题是如何在文章中提到的点重现强制GC?我试图将GC.Collect()放在OperateOnHandle()的开头,并为类C定义了析构函数,但似乎无法正常工作。总是在程序结束时调用析构函数。
@Jon,谢谢你建议我用完调试器。现在,我可以使用调试器的优化版本构建重现本文中描述的问题。它证明了自.NET v1以来这种GC行为没有改变。
我使用的代码:
class C1
{
// Some unmanaged resource handle
IntPtr _handle = IntPtr.Zero;
static void OperateOnHandle(IntPtr h)
{
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("After GC.Collect() call");
// Use the IntPtr here. Oops, invalid operation
}
public void m()
{
OperateOnHandle(_handle);
}
~C1()
{
// Release and destroy IntPtr here
Console.WriteLine("In destructor");
}
}
class Program
{
static void Main(string[] args)
{
C1 aC = new C1();
aC.m();
}
}
输出:
在析构函数中 GC.Collect()之后调用
答案 0 :(得分:2)
请记住,该文章来自2003年,它使用的是CLR v1。我们现在使用CLR v4(虽然没有v3)所以我并不完全惊讶你没有看到完全相同的行为。
目前我甚至无法访问链接页面,也没有包含页面描述内容的描述。是否可能在实例方法结束之前对对象进行垃圾回收?
如果是这样,您可能在重现它时遇到问题的最明显原因是您使用的是调试器。当你在没有连接调试器的情况下运行时,垃圾收集器很多更具侵略性。
这是一个简短但完整的程序,它演示了不在调试器中运行时的问题:
using System;
class ClassWithFinalizer
{
private int value;
public ClassWithFinalizer(int value)
{
this.value = value;
}
~ClassWithFinalizer()
{
Console.WriteLine("Finalizer running!");
}
public void ShowValue()
{
Console.WriteLine(value);
Console.WriteLine("Calling GC.Collect()");
GC.Collect();
Console.WriteLine("Calling GC.WaitForPendingFinalizers()");
GC.WaitForPendingFinalizers();
Console.WriteLine("End of method");
}
}
class Test
{
static void Main()
{
var x = new ClassWithFinalizer(10);
x.ShowValue();
}
}
编译(优化且没有调试符号,只是给它最好的机会!):
csc /o+ /debug- Test.cs
现在运行,输出:
c:\users\Jon\Test>test
10
Calling GC.Collect()
Calling GC.WaitForPendingFinalizers()
Finalizer running!
End of method
注意终结器在方法完成之前如何运行。
使用.NET 4和.NET 3.5进行测试。