原文出自:http://blogs.msdn.com/johan/archive/2007/01/11/i-am-getting-outofmemoryexceptions-how-can-i-troubleshoot-this.aspx
版权归原作者所有,转载请注明出处
如何处理OutOfMemoryException异常
问题:
asp.net应用程序出现OutOfMemoryException异常
解决方案:
使用Windbg查看托管堆
是内存泄漏引起的么?
使用perfmon查看应用程序的内存使用情况.如果内存缓慢上升且从未释放,说明有内存泄漏.如果向过山车一样起起伏伏,基本上是某种操作使用了大量的内存稍后又被垃圾搜集
如何排除故障?
下面一步步描述如何解决此类问题
1.获得内存转储文件
2.打开转储文件然后加载SOS
用windbg打开转储文件然后加载SOS扩展.可以在框架目录下找到,.net2.0下是C:/Windows/Microsoft.NET/Framework/v2.0.50727 ,使用以下命令加载扩展
.load [path]/sos
3.运行dumpheap
运行以下的命令:
!dumpheap -stat
将用四列来显示堆内对象的统计信息
The method table of the object //对象的方法表
The number of objects of this type on the heap //堆上该类型对象的数量
The total size of these objects in bytes //这些对象的总计大小,单位为byte
The name of the object type //对象类型的名称
当心,不要忽略 -stat参数.如果漏掉了此参数,windgb将显示堆上每一个对象的地址。
分析!dumpheap命令提供的信息
下面是例子
0:000> !dumpheap -stat
Statistics:
MT Count TotalSize Class Name
7a787cc4 1 12 System.IO.FileSystemWatcher+FSWAsyncResult
7a75904c 1 12 System.Diagnostics.OrdinalCaseInsensitiveComparer
7a7575cc 1 12 System.CodeDom.Compiler.CodeDomConfigurationHandler
7a7571a8 1 12 System.Net.DefaultCertPolicy
7a75661c 1 12 System.Diagnostics.TraceListenerCollection
7a755834 1 12 System.Diagnostics.PerformanceCounterCategoryType
........CONTINUED.........
68a66a88 227,559 12,743,304 System.Web.UI.WebControls.Literal
68a2f7fc 399,272 14,373,792 System.Web.UI.ControlCollection
68a92e2c 768,731 33,824,164 System.Web.UI.Control+OccasionalFields
68a884a0 641,952 38,517,120 System.Web.UI.LiteralControl
79124228 879,515 43,394,976 System.Object[]
790fa3e0 1,431,594 122,806,484 System.String
Total 10,389,625 objects, Total size: 463,313,540
在这个dump中,有1,431,594个string总计122M,879,515object总计43M,等等.
堆上的object可能会比显示的要大
TotalSize 栏显示的数据并不是100%正确。看看上面位于倒数第三行的LiteralControls 。仅占用了38M,真的只有这么多?TotalSize 指的是对象结构的大小,成员变量如string,integer以及其他子对象并不包含在内。这一列的数据是象征性的,真实数据可能比现实的大得多。 LiteralControl 对象包含不少子对象,其中三个是string,他们的大小在System.String中列出。
使用!dumpobj
让我们仔细看看System.Web.UI.LiteralControls.使用!dumpheap -type System.Web.UI.LiteralControls命令,然后在显示太多行之前快速按下Ctrl+Break
0:000> !dumpheap -type System.Web.UI.LiteralControl
Address MT Size Gen
023ea0a8 68a884a0 60 2 System.Web.UI.LiteralControl
023ea0e4 68a884a0 60 2 System.Web.UI.LiteralControl
023ea374 68a884a0 60 2 System.Web.UI.LiteralControl
023ea460 68a884a0 60 2 System.Web.UI.LiteralControl
023ea510 68a884a0 60 2 System.Web.UI.LiteralControl
023eab3c 68a884a0 60 2 System.Web.UI.LiteralControl
........CONTINUED........
023fe31c 68a884a0 60 2 System.Web.UI.LiteralControl
023fe414 68a884a0 60 2 System.Web.UI.LiteralControl
023fe4c4 68a884a0 60 2 System.Web.UI.LiteralControl
023fe500 68a884a0 60 2 System.Web.UI.LiteralControl
看起来每个LiteralControl大小为60 byte.不过这仅仅是对象结构的大小,不是它所引用的对象和属性的大小.挑一个LiteralControl的地址来执行!dumpobj命令(简写为!do).结果如下:
0:000> !do 023ea0a8
Name: System.Web.UI.LiteralControl
MethodTable: 68a884a0
EEClass: 68a88428
Size: 60(0x3c) bytes
GC Generation: 2
(C:/WINDOWS/assembly/GAC_32/System.Web/2.0.0.0__b03f5f7f11d50a3a/System.Web.dll)
Fields:
MT Field Offset Type VT Attr Value Name
790fa3e0 4001fe0 4 System.String 0 instance 00000000 _id
790fa3e0 4001fe1 8 System.String 0 instance 00000000 _cachedUniqueID
68a2af44 4001fe2 c ...em.Web.UI.Control 0 instance 023e8864 _parent
68a91070 4001fe3 2c System.Int32 0 instance 0 _controlState
68a85ea0 4001fe4 10 ...m.Web.UI.StateBag 0 instance 00000000 _viewState
68a2af44 4001fe5 14 ...em.Web.UI.Control 0 instance 023e8864 _namingContainer
68a273d0 4001fe6 18 System.Web.UI.Page 0 instance 01df4514 _page
68a92e2c 4001fe7 1c ...+OccasionalFields 0 instance 00000000 _occasionalFields
68a2b378 4001fe8 20 ...I.TemplateControl 0 instance 00000000 _templateControl
68a14528 4001fe9 24 ...m.Web.VirtualPath 0 instance 00000000 _templateSourceVirtualDirectory
68a8bb48 4001fea 28 ...rs.ControlAdapter 0 instance 00000000 _adapter
68a3a8f8 4001feb 30 ...SimpleBitVector32 1 instance 023ea0d8 flags
790f9c18 4001fda c70 System.Object 0 shared static EventDataBinding
>> Domain:Value 000f0d00:NotInit 0011a720:01df0028 <<
790f9c18 4001fdb c74 System.Object 0 shared static EventInit
>> Domain:Value 000f0d00:NotInit 0011a720:01df0034 <<
790f9c18 4001fdc c78 System.Object 0 shared static EventLoad
>> Domain:Value 000f0d00:NotInit 0011a720:01df0040 <<
790f9c18 4001fdd c7c System.Object 0 shared static EventUnload
>> Domain:Value 000f0d00:NotInit 0011a720:01df004c <<
790f9c18 4001fde c80 System.Object 0 shared static EventPreRender
>> Domain:Value 000f0d00:NotInit 0011a720:01df0058 <<
790f9c18 4001fdf c84 System.Object 0 shared static EventDisposed
>> Domain:Value 000f0d00:NotInit 0011a720:01df0064 <<
79124228 4001fec c88 System.Object[] 0 shared static automaticIDs
>> Domain:Value 000f0d00:NotInit 0011a720:01df0070 <<
790fa3e0 4002211 34 System.String 0 instance 02238664 _text
用!do来查看text属性.
0:000> !do 02238664
Name: System.String
MethodTable: 790fa3e0
EEClass: 790fa340
Size: 158(0x9e) bytes
GC Generation: 2
(C:/WINDOWS/assembly/GAC_32/mscorlib/2.0.0.0__b77a5c561934e089/mscorlib.dll)
String: </td>
</tr>
</table>
<!-- end of content table -->
Fields:
MT Field Offset Type VT Attr Value Name
790fed1c 4000096 4 System.Int32 0 instance 71 m_arrayLength
790fed1c 4000097 8 System.Int32 0 instance 70 m_stringLength
790fbefc 4000098 c System.Char 0 instance 3c m_firstChar
790fa3e0 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000f0d00:790d6584 0011a720:790d6584 <<
79124670 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000f0d00:01d413b8 0011a720:01d44f80 <<
可以看到,这个字符串包括闭合table的数据.也可以查看其他希望查看的属性,但这儿有一个非常有用的命令:
使用!objsize
有办法查看System.Web.UI.LiteralControl的总大小么?-非常简单!用!objsize命令.!objsize命令计算一个对象内部所有指针的大小.下面是!objsize命令的内部文档说明:
0:000> !help objsize
-------------------------------------------------------------------------------
!ObjSize [<对象地址>]
如果不指定参数,!ObjSize命令列出托管线程上所有的对象大小.同时枚举出进程内所有 GCHandle,并且合计出这些handle指向的所有对象的大小.在计算对象大小的时候,!ObjSize将所有子对象的大小加到父对象上
举个例子, !DumpObj 列出了Customer对象的大小为20字节
0:000> !do a79d40
Name: Customer
MethodTable: 009038ec
EEClass: 03ee1b84
Size: 20(0x14) bytes
(C:/pub/unittest.exe)
Fields:
MT Field Offset Type Attr Value Name
009038ec 4000008 4 CLASS instance 00a79ce4 name
009038ec 4000009 8 CLASS instance 00a79d2c bank
009038ec 400000a c System.Boolean instance 1 valid
but !ObjSize lists 152 bytes:
0:000> !ObjSize a79d40
sizeof(00a79d40) = 152 ( 0x98) bytes (Customer)
但!ObjSize显示为152字节
这是因为一个Customer对象引用了一个Bank对象, 有一个name属性,Bank对象引用一个Address字符串.可以使用!ObjSize来确定任何特定对象,比如web server上的托管缓存
堆上的对象的大小可能比显示出来的小
那么如果我们使用!objsize来查看LiteralControl会得到什么?非常有趣,因为会发生的是;调试器会忙碌相当一段时间,最后得到以下的结果:
0:000> !objsize 023ea0a8
sizeof(023ea0a8) = 456918136 ( 0x1b3c0478) bytes (System.Web.UI.LiteralControl)
456M!这怎么可能?如果回头看看用!do命令查看LiteralControl的地方,将看到这个控件拥有对page的引用,page有对cache的引用,这样将得到几乎对整个堆的引用
摘要
期望此文能让你对sos扩展提供的三个简单命令能做些什么有快速的大概了解,这些命令是:
!dumpheap
!dumpobj
!objsize
版权归原作者所有,转载请注明出处
如何处理OutOfMemoryException异常
问题:
asp.net应用程序出现OutOfMemoryException异常
解决方案:
使用Windbg查看托管堆
是内存泄漏引起的么?
使用perfmon查看应用程序的内存使用情况.如果内存缓慢上升且从未释放,说明有内存泄漏.如果向过山车一样起起伏伏,基本上是某种操作使用了大量的内存稍后又被垃圾搜集
如何排除故障?
下面一步步描述如何解决此类问题
1.获得内存转储文件
2.打开转储文件然后加载SOS
用windbg打开转储文件然后加载SOS扩展.可以在框架目录下找到,.net2.0下是C:/Windows/Microsoft.NET/Framework/v2.0.50727 ,使用以下命令加载扩展
.load [path]/sos
3.运行dumpheap
运行以下的命令:
!dumpheap -stat
将用四列来显示堆内对象的统计信息
The method table of the object //对象的方法表
The number of objects of this type on the heap //堆上该类型对象的数量
The total size of these objects in bytes //这些对象的总计大小,单位为byte
The name of the object type //对象类型的名称
当心,不要忽略 -stat参数.如果漏掉了此参数,windgb将显示堆上每一个对象的地址。
分析!dumpheap命令提供的信息
下面是例子
0:000> !dumpheap -stat
Statistics:
MT Count TotalSize Class Name
7a787cc4 1 12 System.IO.FileSystemWatcher+FSWAsyncResult
7a75904c 1 12 System.Diagnostics.OrdinalCaseInsensitiveComparer
7a7575cc 1 12 System.CodeDom.Compiler.CodeDomConfigurationHandler
7a7571a8 1 12 System.Net.DefaultCertPolicy
7a75661c 1 12 System.Diagnostics.TraceListenerCollection
7a755834 1 12 System.Diagnostics.PerformanceCounterCategoryType
........CONTINUED.........
68a66a88 227,559 12,743,304 System.Web.UI.WebControls.Literal
68a2f7fc 399,272 14,373,792 System.Web.UI.ControlCollection
68a92e2c 768,731 33,824,164 System.Web.UI.Control+OccasionalFields
68a884a0 641,952 38,517,120 System.Web.UI.LiteralControl
79124228 879,515 43,394,976 System.Object[]
790fa3e0 1,431,594 122,806,484 System.String
Total 10,389,625 objects, Total size: 463,313,540
在这个dump中,有1,431,594个string总计122M,879,515object总计43M,等等.
堆上的object可能会比显示的要大
TotalSize 栏显示的数据并不是100%正确。看看上面位于倒数第三行的LiteralControls 。仅占用了38M,真的只有这么多?TotalSize 指的是对象结构的大小,成员变量如string,integer以及其他子对象并不包含在内。这一列的数据是象征性的,真实数据可能比现实的大得多。 LiteralControl 对象包含不少子对象,其中三个是string,他们的大小在System.String中列出。
使用!dumpobj
让我们仔细看看System.Web.UI.LiteralControls.使用!dumpheap -type System.Web.UI.LiteralControls命令,然后在显示太多行之前快速按下Ctrl+Break
0:000> !dumpheap -type System.Web.UI.LiteralControl
Address MT Size Gen
023ea0a8 68a884a0 60 2 System.Web.UI.LiteralControl
023ea0e4 68a884a0 60 2 System.Web.UI.LiteralControl
023ea374 68a884a0 60 2 System.Web.UI.LiteralControl
023ea460 68a884a0 60 2 System.Web.UI.LiteralControl
023ea510 68a884a0 60 2 System.Web.UI.LiteralControl
023eab3c 68a884a0 60 2 System.Web.UI.LiteralControl
........CONTINUED........
023fe31c 68a884a0 60 2 System.Web.UI.LiteralControl
023fe414 68a884a0 60 2 System.Web.UI.LiteralControl
023fe4c4 68a884a0 60 2 System.Web.UI.LiteralControl
023fe500 68a884a0 60 2 System.Web.UI.LiteralControl
看起来每个LiteralControl大小为60 byte.不过这仅仅是对象结构的大小,不是它所引用的对象和属性的大小.挑一个LiteralControl的地址来执行!dumpobj命令(简写为!do).结果如下:
0:000> !do 023ea0a8
Name: System.Web.UI.LiteralControl
MethodTable: 68a884a0
EEClass: 68a88428
Size: 60(0x3c) bytes
GC Generation: 2
(C:/WINDOWS/assembly/GAC_32/System.Web/2.0.0.0__b03f5f7f11d50a3a/System.Web.dll)
Fields:
MT Field Offset Type VT Attr Value Name
790fa3e0 4001fe0 4 System.String 0 instance 00000000 _id
790fa3e0 4001fe1 8 System.String 0 instance 00000000 _cachedUniqueID
68a2af44 4001fe2 c ...em.Web.UI.Control 0 instance 023e8864 _parent
68a91070 4001fe3 2c System.Int32 0 instance 0 _controlState
68a85ea0 4001fe4 10 ...m.Web.UI.StateBag 0 instance 00000000 _viewState
68a2af44 4001fe5 14 ...em.Web.UI.Control 0 instance 023e8864 _namingContainer
68a273d0 4001fe6 18 System.Web.UI.Page 0 instance 01df4514 _page
68a92e2c 4001fe7 1c ...+OccasionalFields 0 instance 00000000 _occasionalFields
68a2b378 4001fe8 20 ...I.TemplateControl 0 instance 00000000 _templateControl
68a14528 4001fe9 24 ...m.Web.VirtualPath 0 instance 00000000 _templateSourceVirtualDirectory
68a8bb48 4001fea 28 ...rs.ControlAdapter 0 instance 00000000 _adapter
68a3a8f8 4001feb 30 ...SimpleBitVector32 1 instance 023ea0d8 flags
790f9c18 4001fda c70 System.Object 0 shared static EventDataBinding
>> Domain:Value 000f0d00:NotInit 0011a720:01df0028 <<
790f9c18 4001fdb c74 System.Object 0 shared static EventInit
>> Domain:Value 000f0d00:NotInit 0011a720:01df0034 <<
790f9c18 4001fdc c78 System.Object 0 shared static EventLoad
>> Domain:Value 000f0d00:NotInit 0011a720:01df0040 <<
790f9c18 4001fdd c7c System.Object 0 shared static EventUnload
>> Domain:Value 000f0d00:NotInit 0011a720:01df004c <<
790f9c18 4001fde c80 System.Object 0 shared static EventPreRender
>> Domain:Value 000f0d00:NotInit 0011a720:01df0058 <<
790f9c18 4001fdf c84 System.Object 0 shared static EventDisposed
>> Domain:Value 000f0d00:NotInit 0011a720:01df0064 <<
79124228 4001fec c88 System.Object[] 0 shared static automaticIDs
>> Domain:Value 000f0d00:NotInit 0011a720:01df0070 <<
790fa3e0 4002211 34 System.String 0 instance 02238664 _text
用!do来查看text属性.
0:000> !do 02238664
Name: System.String
MethodTable: 790fa3e0
EEClass: 790fa340
Size: 158(0x9e) bytes
GC Generation: 2
(C:/WINDOWS/assembly/GAC_32/mscorlib/2.0.0.0__b77a5c561934e089/mscorlib.dll)
String: </td>
</tr>
</table>
<!-- end of content table -->
Fields:
MT Field Offset Type VT Attr Value Name
790fed1c 4000096 4 System.Int32 0 instance 71 m_arrayLength
790fed1c 4000097 8 System.Int32 0 instance 70 m_stringLength
790fbefc 4000098 c System.Char 0 instance 3c m_firstChar
790fa3e0 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000f0d00:790d6584 0011a720:790d6584 <<
79124670 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000f0d00:01d413b8 0011a720:01d44f80 <<
可以看到,这个字符串包括闭合table的数据.也可以查看其他希望查看的属性,但这儿有一个非常有用的命令:
使用!objsize
有办法查看System.Web.UI.LiteralControl的总大小么?-非常简单!用!objsize命令.!objsize命令计算一个对象内部所有指针的大小.下面是!objsize命令的内部文档说明:
0:000> !help objsize
-------------------------------------------------------------------------------
!ObjSize [<对象地址>]
如果不指定参数,!ObjSize命令列出托管线程上所有的对象大小.同时枚举出进程内所有 GCHandle,并且合计出这些handle指向的所有对象的大小.在计算对象大小的时候,!ObjSize将所有子对象的大小加到父对象上
举个例子, !DumpObj 列出了Customer对象的大小为20字节
0:000> !do a79d40
Name: Customer
MethodTable: 009038ec
EEClass: 03ee1b84
Size: 20(0x14) bytes
(C:/pub/unittest.exe)
Fields:
MT Field Offset Type Attr Value Name
009038ec 4000008 4 CLASS instance 00a79ce4 name
009038ec 4000009 8 CLASS instance 00a79d2c bank
009038ec 400000a c System.Boolean instance 1 valid
but !ObjSize lists 152 bytes:
0:000> !ObjSize a79d40
sizeof(00a79d40) = 152 ( 0x98) bytes (Customer)
但!ObjSize显示为152字节
这是因为一个Customer对象引用了一个Bank对象, 有一个name属性,Bank对象引用一个Address字符串.可以使用!ObjSize来确定任何特定对象,比如web server上的托管缓存
堆上的对象的大小可能比显示出来的小
那么如果我们使用!objsize来查看LiteralControl会得到什么?非常有趣,因为会发生的是;调试器会忙碌相当一段时间,最后得到以下的结果:
0:000> !objsize 023ea0a8
sizeof(023ea0a8) = 456918136 ( 0x1b3c0478) bytes (System.Web.UI.LiteralControl)
456M!这怎么可能?如果回头看看用!do命令查看LiteralControl的地方,将看到这个控件拥有对page的引用,page有对cache的引用,这样将得到几乎对整个堆的引用
摘要
期望此文能让你对sos扩展提供的三个简单命令能做些什么有快速的大概了解,这些命令是:
!dumpheap
!dumpobj
!objsize