我有一个应用程序存在内存泄漏问题,这是由于在将对象引用设置为null之前未解除事件绑定。该应用程序相当大,通过查看代码很难找到内存泄漏的位置。我想使用sos.dll来查找导致泄漏的方法名称,但我卡住了。我设置了一个测试项目来展示这个问题。
这里有两个类,其中一个有一个事件,另一个监听该事件,代码如下:
namespace MemoryLeak
{
class Program
{
static void Main(string[] args)
{
TestMemoryLeak testMemoryLeak = new TestMemoryLeak();
while (!Console.ReadKey().Key.Equals('q'))
{
}
}
}
class TestMemoryLeak
{
public event EventHandler AnEvent;
internal TestMemoryLeak()
{
AnEventListener leak = new AnEventListener();
this.AnEvent += (s, e) => leak.OnLeak();
AnEvent(this, EventArgs.Empty);
}
}
class AnEventListener
{
public void OnLeak()
{
Console.WriteLine("Leak Event");
}
}
}
我进入代码,然后在中间窗口输入.load sos.dll
然后我使用 !dumpheap 命令获取类型为 AnEventListener 的对象在堆中的情况
!dumpheap -type MemoryLeak.AnEventListener
然后我得到了以下结果
PDB symbol for mscorwks.dll not loaded
Address MT Size
01e19254 0040348c 12
total 1 objects
Statistics:
MT Count TotalSize Class Name
0040348c 1 12 MemoryLeak.AnEventListener
Total 1 objects
我使用!gcroot来确定为什么对象没有被垃圾回收
!gcroot 01e19254
并获得以下内容
!gcroot 01e19254
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Error during command: Warning. Extension is using a callback which Visual Studio
does not implement.
Scan Thread 5208 OSTHread 1458
ESP:2ef3cc:Root:01e19230(MemoryLeak.TestMemoryLeak)->
01e19260(System.EventHandler)->
01e19248(MemoryLeak.TestMemoryLeak+<>c__DisplayClass1)->
01e19254(MemoryLeak.AnEventListener)
Scan Thread 7376 OSTHread 1cd0
现在我可以看到导致内存泄漏的事件处理程序。我使用 !do 查看事件处理程序的字段并获取
!do 01e19260
Name: System.EventHandler
MethodTable: 65129dc0
EEClass: 64ec39d0
Size: 32(0x20) bytes
(C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
MT Field Offset Type VT Attr Value Name
65130770 40000ff 4 System.Object 0 instance 01e19248 _target
6512ffc8 4000100 8 ...ection.MethodBase 0 instance 00000000 _methodBase
6513341c 4000101 c System.IntPtr 1 instance 0040C060 _methodPtr
6513341c 4000102 10 System.IntPtr 1 instance 00000000 _methodPtrAux
65130770 400010c 14 System.Object 0 instance 00000000 _invocationList
6513341c 400010d 18 System.IntPtr 1 instance 00000000 _invocationCount
所以现在我可以看到指向未被分离的方法的指针。
0040C060 _methodPtr
但是我该如何获取那个方法的名称?