《Advanced .NET Debugging》 读书笔记 Listing 5-4: 具有Finalize方法的简单对象
时间:2011-01-06 来源:李志鹏
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace Advanced.NET.Debugging.Chapter5
{
class NativeEvent
{
private IntPtr nativeHandle;
public IntPtr NativeHandle { get { return nativeHandle; } }
public NativeEvent(string name)
{
nativeHandle = CreateEvent( IntPtr.Zero,
false,
true,
name);
}
~NativeEvent()
{
if(nativeHandle!=IntPtr.Zero)
{
CloseHandle(nativeHandle);
nativeHandle=IntPtr.Zero;
}
}
[DllImport("kernel32.dll")]
static extern IntPtr CreateEvent(IntPtr attribs, bool manual, bool initial, string name);
[DllImport("kernel32.dll")]
static extern IntPtr CloseHandle(IntPtr handle);
}
class Finalize
{
static void Main(string[] args)
{
Finalize f = new Finalize();
f.Run(args);
}
public void Run(string[] args)
{
NativeEvent nEvent = new NativeEvent("MyNewEvent");
//
// Use nEvent
//
nEvent = null;
Console.WriteLine("Press any key to GC");
Console.ReadLine();
GC.Collect();
Console.WriteLine("Press any key to GC");
Console.ReadLine();
GC.Collect();
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
}
}
程序中的NativeEvent类是一个带Finalize方法的类。这种类的特点是,要经过两次GC回收才会被彻底release,会存在一个简短的”复活“的过程。第一次GC之后,该对象在Finalization Queue上的引用会被移除,转而被F-reachable queue引用。在第二次GC之前,程序会起一个执行Finalize的thread来专门执行Finalizae方法。执行完毕之后,该对象的引用彻底消失,此时再次执行GC,对象才能被彻底释放。
1. 在WinDbg里面调入05Finalize.exe
2. 执行 .symfix
3. 执行 .loadby sos.dll mscorwks
4. 执行!FinalizeQueue
可见此时处于代龄0的对象有30个,处于F-reachable的对象有0个
5. 执行 ~*kn 查看stack trace,可找到即将执行到
找到里面存在的FinalizethreadWorker
6. 根据第五步找到的设置断点,执行 bp 000007fef7cf7e0a
7.执行 g, 到断点处,执行 !finalizequeue
可见此时对象的数量变少,因为被回收了,未被回收的代龄增加,而此时F-reachable的引用有两个,表明NativeEvent对象在F-reachable上有了引用
8. 执行g, 再次执行 !finalizequque:
可见在Finalize方法执行之后,F-reachable上的引用已经消失。
9. 再次执行 !finalizequeue:
可见在又一次的gc之后,剩余有引用的对象,代龄再次增加,变成了代龄2.