捉虫记(一)GC堆中的“内存泄漏”

上一篇 / 下一篇  2012-08-17 10:15:15 / 个人分类:杂谈

?5o[z"y(E}2g#S0  首先介绍一下程序,Server程序,同时有好多Client连接,Client用tcpSocket发送数据给Server,Server对 数据进行处理并返回处理结果给Client。虽然整个程序的开发时间很长,但中间不停的需求变更,功能不停地增加减少,代码也是好多人,每人几个模块甚至 是几个函数杂凑起来,系统正在被使用,功能也不断被增加,总之......是一个SHZY初级阶段特色的绝对代表的Server程序。

dH Y*h*Ha e-^ p;a"D0

%SI dt;{IF*l0  这是我接手这个程序之后的一些Bug的发现和修改,把他记录下来,以做茶余饭后的谈资。

Qt,V N1F8R V0

T6CT;Z ^["w(Ur4U0  对于这种要文档没文档、要规范没规范程序,要在一边添加新功能,一边发现和修改bug是极其困难的,如果没有一些大杀器,不太好搞,而一但有了一些大杀器,对于有些问题的发现以及解决又简单到令人发指,WinDbg就是这样一种大杀器。51Testing软件测试网:~eL qI)G

51Testing软件测试网l4Sz0X:@K{5y

   程序一天部署好几次,没办法,bug太多了,催的又急,每次修改一下就赶紧部署了,某天突然有个经理电话里喊道,你这程序内存怎么越用越大,幸好哥早有 防备,呃,经理,先别着急,请双击一下桌面的“Server.Bat”,然后重新启动一下程序(重新启动一下内存就小了哈)。51Testing软件测试网jK)^]{V

51Testing软件测试网a&h"IqPp&u

  1、首先对程序的运行有个大概的了解。(比如说 程序运行了多长时间,内存多大)

"w}U^4c r1u`?PJ0

(Ky,q)R9m*U(g$F0zL2m!l0  登到服务器上一看,我的天, dump文件1.8G---程序大概是2个小时之前部署

1X@Td3U"KL051Testing软件测试网"ljN5b.I2v9_*e1u

  打开windbg,打开dump,呃,程序运行了2个半小时。51Testing软件测试网Wo*e{!V _9{O}S

51Testing软件测试网1UY0|Ej

  设置上符号地址,然后加载sos

6H/R2~Jf]2[ X0

  2、查看GC堆上的内存占用是多大。(一般来讲,内存泄露都是GC堆上的问题,也就是说new了一些对象在某些情况下没有释放,!EEHeap -GC 正是查看GC堆得命令,我们看到

s-`!g9u#tu8d~cf0

  最后一行GC Heap Size是1.2G,1.8G的内存,GC堆1.2G,肯定有问题了,当然,Loader堆也不大可能有600M,以后我会对Loader堆继续分析。。。)51Testing软件测试网 O t;Jk#^]

  第一个命令  !EEHeap -GC51Testing软件测试网A/\-xn V2X+C o

*s;i-y9b2t?o,`0

  3、确定是GC堆的问题,就看看GC堆上存活的对象是那些。(!dumpheap -stat 就是GC堆上的统计,我们看到统计结果,第一行SingnallingContex,  00000644803111a0  是该对象的MethondTable的地址,而186402是该对象在内存中的个数,35789184是大小,这是纯净的大小,该对象里面所包含的对象的 大小不算在内,看到Context相关联的ProcessDetail竟然有5325513个,所占字节为488804488,这足够惊人了。。。)

7e\ Z\/e M oN0

  呃,看到这里都能猜想到,Loader堆里肯定有很多垃圾,先不管这么多了[我会在后续中介绍Loader堆里面的事情],先看看GC堆里有什么,第二个命令!DumpHeap -stat。51Testing软件测试网&Y`;X'?4?8@;Qr;JnCn

3`^a)l^ E0

   看到一个很熟悉的名字 “SingallingContext”,这是一个Context,这个Context是接收到数据之后包装一下经过业务的pipfilter。1W多 个,而Context上多呆的ProcessDetail竟然到了百万,猜测是某个处理Module缓存住了,没有释放。51Testing软件测试网1h'Y3w3Wv`5cC-h E |

51Testing软件测试网'v4J&quZ9d bY_

  4、确定了是哪种类型对象的问题,那就看看该对象。( !Dumpheap -mt 00000644803111a0  你也可以用 !Dumpheap -type SingnallingContex 这个命令)

0B*Z~zA;M\U0

N)n/M{NotC0  于是 第三个命令 !Dumpheap -mt 00000644803111a051Testing软件测试网-o,zmEB H]

51Testing软件测试网7{c~+~p/ZgM+tV

  5、找到其中一个对象,看看是因为谁的引用而没有释放(!gcroot +对象地址 这个命令就可以得到这个对象的“根”,这个过程会非常长,具体讲该命令将会遍历所有的根,我们看到Scan Thread 67 实际上就是在扫描67号线程的线程Stack是不是引用了该对象。)。51Testing软件测试网 VNPw3}

  额,这么多,随便找一个,就找最后一个吧,第四个命令 !gcroot 00000001677ceda8,这个时候该去厕所抽支烟....

i$Lm%a9Y#Yxo0

51Testing软件测试网%Oo{dw

  6、我们找到了“罪魁祸首”的对象,一般我们看看代码就OK了。(这里闲的无聊的话我们可以看看这个对象到底占了多大的内存,!objsize +对象地址,我们就看到了,这个命令时间非常长,长到你可以蹲着抽烟)

cSF5bl3R+`5K ]0

  额,看到根了,SingallingContextTracer,这个东西是个跟踪器,不会是跟踪器没有释放吧??先不管,看看多大,第五个命令 !objsize 00000000c170765851Testing软件测试网IwK ao:~

51Testing软件测试网3|7scr2u7|+V

  打开代码,找到SingallingContextTracer,呃,这个可怜的家伙把每个Context放到自己 的Queue中,然后开启另外的线程来处理,可惜处理线程被谁注释掉了(跟踪功能因为没啥用处,被去掉了,但是去掉了应该不让入队啊),好吧,赶紧修改代 码,重新部署......51Testing软件测试网D+]D+B#|ug^ m&C,p

  -----------------------------------------------------------------------------------------------------51Testing软件测试网$`,eS?J

  总结:51Testing软件测试网~_oQlZ]

  1、对程序大概了解,知己知彼。51Testing软件测试网*E%A[jE%j0^

  2、确定什么地方引起的泄露,是GC堆还是什么Loader堆等。51Testing软件测试网*DbL d#[V

  3、确定是哪种类型引起的泄露,其实可以dump两次,然后通过比较两次对象的不同,更加明显看出是那个类型的对象出了问题。

qR1B `.|a,e@X0

  4、找到该对象。51Testing软件测试网de#GI:Ld _8h

  5、找到该对象的root。

K:k+W-Y:}.?l&q0

  root都找到了,剩下的问题就都好解决了。

TT \fai"i)g0

TAG:

 

评分:0

我来说两句

Open Toolbar