Always Debug

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  7 随笔 :: 0 文章 :: 38 评论 :: 0 引用

几天前写的[Debug实践]windbg+性能监视器解决一个内存泄漏问题(非托管资源)  随笔中,解决了一个非托管资源泄漏的问题,加一个兄弟篇:)
现象:服务器内存占用突发性升高,从任务管理器中看w3wp.exe占用内存1G多,CPU占用率不高
分析过程:
这些年来碰到的大多数内存占用过高问题都是托管资源类的,看到系统中的报警,第一直觉便是采集服务器上的dump文件。

不过这应该算是一个坏习惯,有条件的朋友,推荐先用性能监视器看看private bytes,virtual bytes,bytes in all heaps几条线的趋势。
如果bytes in all heaps曲线的上升趋势与private bytes相似则应该为托管内存的泄漏。

(1)用debugdiag进行设定了一个内存监控,之后放手去做其他的事,大约三个多小时后,运维部门通知我逮到一个dmp文件。
部分朋友可能没有权限在服务器上装软件,但运行一个vbs脚本应该没有问题,在几天前的文章中我发了一个自己用的脚本,详见vbscript监控进程内存,高内存占用时利用ntsd生成dump文件

(2)用windbg打开dmp文件,用!eeheap -gc命令看看托管堆的大小:
000de168   496274     47951740      Free
7912d8f8   223673     91432880 System.Object[]
790fd8c4  6927606    293122996 System.String
79114cc0  4842011    309888704 System.Runtime.Serialization.ObjectHolder
托管堆的内存大小占了900m左右,看来问题就出在System.Runtime.Serialization.ObjectHolder上。

(3)为了找到问题的根源,从metatable 79114cc0中找出一个ObjectHolder实例来看一下
运行!dumpheap -mt 79114cc0  ...省略一大堆内容
从里面随便找了个ObjectHolder,用!do 看了一下发现它有个string类型的属性,内存地址为234ac9b8
因为是托管的资源,用!gcroot命令看它的引用关系:
ESP:1d6f47c:Root:4379d434(System.Web.HttpRequest)->
4379d378(System.Web.HttpContext)->
41cfc750(ASP.global_asax)->
4379d664(System.Web.HttpAsyncResult)->
06688b34(System.AsyncCallback)->
06688828(System.Web.HttpRuntime)->
066888dc(System.Web.RequestTimeoutManager)->
06688900(System.Object[])->
06688a34(System.Web.Util.DoubleLinkList)->
05654488(System.Web.RequestTimeoutManager+RequestTimeoutEntry)->
05653fdc(System.Web.HttpContext)->
05657b14(ASP.service_searchticketrefundlist_aspx)->
05658728(ASP.service_modules_searchservicesalesorder_ascx)->
05678f6c(System.Data.DataTable)->
05679128(System.Data.DataColumnCollection)->
05679178(System.Collections.Hashtable)->
0567a10c(System.Collections.Hashtable+bucket[])->
056798f4(System.Data.DataColumn)->
2a03b804(System.Data.Common.StringStorage)->
12f90098(System.Object[])->
234ac9b8(System.String)
以及
ESP:111ee210:Root:2a03b768(System.Collections.Generic.List`1+Enumerator[[Com.*****.***.DataTransferObject.AfterService.OrderSearchResult, DataTransferObject.Flight]])->
056e9f84(System.Collections.Generic.List`1[[Com.*****.***.DataTransferObject.AfterService.OrderSearchResult, DataTransferObject.Flight]])->
14e60038(System.Object[])->
234ac858(Com.*****.***.DataTransferObject.AfterService.OrderSearchResult)->
234ac9b8(System.String)

0:000> !objsize 14e60038
sizeof(14e60038) =    222303448 (   0xd4014d8) bytes (System.Object[])
可以看到这个14e60038(System.Object[])->的大小达到了200多兆
这个时候其实已经可以大致定位到出问题的页面

05657b14(ASP.service_searchticketrefundlist_aspx)->
05658728(ASP.service_modules_searchservicesalesorder_ascx)->
以及这个可疑对象:OrderSearchResult

(4)与相关开发人员确认,这是一个查询订单的页面,而部分会员的订单数量很大,没有做相应的控制。
如果用debugdiag提供的报表还可以看到被堵塞的http请求:
Client connection from *****:***to 192.168.1.2:80 
Host Header   *****.com:80
POST request for   /*****/*******.aspx?id=422
Mapped To URL   /*******.aspx
HTTP Version   HTTP/1.1
SSL Request   False
Time alive   00:06:16
QueryString   id=422
Request mapped to   
HTTP Request State   HTR_READING_CLIENT_REQUEST
Native Request State   NREQ_STATE_PROCESS

posted on 2009-06-12 20:59 dbgeng 阅读(...) 评论(...) 编辑 收藏