.Net 使用sos.dll调式OutOfMemoryException
做了几年的.net开发,还是第一次实际碰到抛出OutOfMemoryException的情况,做了一下代码检查,没有发现什么问题,就决定用sos.dll调试一下。
sos.dll是一个扩展库,用来帮助在visual studio或者windows debugger(WinDbg.exe)里面调试managed的程序,它可以提供CLR内部的情况。对于内存耗尽这种现象,很可能是因为有root还指向着对象而没有被垃圾回收,如果你从代码里面不能很容易找出是哪里,sos.dll应该能帮助解决这类问题。
使用Sos.dll也很简单,首先使用WinDbug.exe attach到要调试的程序上,然后load sos.dll,如下图:
我们这次碰到的OutOfMemoryException是很快出现的,考虑是由于大的对象造成里,我们程序里使用了一个16M的字节数组,使用命令 !DumpHeap -min 1000000列出堆里大于1百万个字节的对象, 输出如下图:
从里面看到确实是有几个16M的对象,随便找一个对象使用命令GCRoot查看它的root,输出如下图:
从结果里看到这个对象确实还有root指着它,简单分析了一下,猜测可能跟使用SocketAsyncEventArgs对象有关系,Google了一下,发现其他人也碰到过类似的情况,由于使用SocketAsyncEventArgs不当造成内存泄漏。修改了一下程序,显式的调用了SocketAsyncEventArgs的Dispose,问题解决。
SocketAsyncEventArgs对象实现了IDispose模式,按道理来说,如果没有直接调用Dispose,会在Finalize的时候释放资源,但是SocketAsyncEventArgs对象比较特殊,必须显式的调用Dispose,否则就可能造成内存泄漏,这个对象里面封装了一个东西,会提交给IO完成端口,实现上比较特殊。
总结:
- 如果碰到奇怪的内存问题,从代码上没有看出来什么原因,可以考虑使用sos.dll进行调试。
- SocketAsyncEventArgs对象有可能造成内存泄漏。