发现并解决ASP.NET内存耗尽(OOM),让服务器"永不重启"

来源:http://www.cnblogs.com/koumi/archive/2010/10/12/1849077.html

========下面的一堆文字为了说明一件事情---.NET程序,内存溢出,如何控制.主要是堆HEAP大小如何控制以及优化.以减轻GC突发性负担及这个时候服务器当机的可能*.
对于大型程序,完全依赖GC是不现实的,对于高负载服务器,往往我们80%的堆都由自己的析构函数接管,并辅助以自行设计的bufferpool接管堆释放工作以达到HEAP可控的目的,减少CPU突发性负荷(CPU尖峰).虽然不像C那样可以控制的那么完全,但是多多少少对OOM的发生起到抑制作用,深入下去可以完全避免OOM......好了IF性能和内存开销没什么追求的 THEN 就不必看了,,,,

ELSE

GO

=====================
1.下个windbg,去baidu google一下即可..
2.sos.dll 这个框架自带,只所以提下,是让大家有搜索的关键字用.
3.泄露,对于.net程序,主要是堆泄露,对于大型服务器程序,需要严格排查OOM(内存泄露)的问题,节约服务器GC开销,内存开销,cpu开销,提高支撑
4.配置环境变量 添加系统变量 _NT_DEBUGGER_EXTENSION_PATH   C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727  这个是为了能够找到sos.dll
5.实战
启动windbg,开启调试窗口,加载用于.NET调试所使用的sos.dll
.load sos
回车之后无任何显示表示无任何错误,这个时候就可以运行调试命令了.
需要说明的是.打头的是windbg自带命令,!打头的命令是sos.dll调试命令.

 

显示GC堆占用情况命令  !dumpheap -stat
大概会显示这些:对象表,对象数量,每个对象内存占用情况...等,如下:
---------------------
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
..................
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
----------------------

 

 

1,431,594 个 System.String对象 占用 122 MBytes

 

 

使用!dumpobj 可以查看System.String对象构成情况

 

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

 

随便抓个控件的地址来分析!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 + 地址 来进入查看,以便找到OOM的根源..试试

 

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:       
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 <<

 

可以看到32位地址为02238664的是用于表格的结束标志存储.

 

使用!objsize进一步命令查看对象内的的对象构成,精确到class名,自己可以试试了...还有很多命令可以查看Gen的回收情况,对于长时间未释放的unmanaged资源也可以列表出来,这个时候可以do进去,查看内部结构,找到属于哪段代码之后,再返回自己的.cs代码进行逻辑调整....这样的话,性能就很可观了.同时可以尽量使用好CPU,而不必让不必要的CPU时间牺牲框架和底层的代码胶合层上面..永远要记住CPU时间是用户的,不是你的!这样,对内存了解的多一些,你的程序就能跑的更快一点,持久运行的时间就更长一些...

 

通常,asp.net或者socket服务器运行的时候,对内存的要求是比较高的,如果内存的性能我们不能去把握,真的很难再生产环境中超越LAMP体系架构.
我的观点是,内存---能节约,尽量节约吧,能高效利用,尽量高效利用!所以写这篇帖子,非常非常肤浅的介绍了下,前后也就写了20分钟,因为要睡觉了...

 

----[成都]CCCP苏联程序员

 

 

对了可以去买本"windows调试技术"来看 http://bbs.dbgtech.net/forumdisplay.php?fid=16 可以先了解下.

技术交流群欢迎您的加入!QQ群:29123371
posted on 2010-10-16 22:54  TsingCai  阅读(768)  评论(0编辑  收藏  举报