一、问题现象
从截图现象看,应用程序CPU和内存都上去了。并且还是导致程序崩溃了。这时我想到了在老师(一线码农)那里学到的分析办法,先抓取一个Dump。然后仔细分析。
二、分析Dump
通过Address -summary命令,查看内存确实偏高,并且都在托管堆中。
2.1 确认CPU是否真的存在跑高的的现象
通过!tp 查看CPU 确实偏高
三、分析内存泄漏问题
3.1 通过!dumpheap -stat 命令,看看内存中对象分配情况
从上图,不难看出Seismic.Core.TraceData的数量挺多的,837 546 144(8亿多个对象),有点恐怖。
3.2 查找Seismic.Core.TraceData对象的持有者
通过dumobj命令,可以看到对象的字段信息,是一个时间和一个浮点数。
3.3. 然后通过 !gcroot命令,查看对象的引用链
发现此对象被 "4B5C"线程持有,并且在做Clone处理
3.4 找到对应Dll的相关方法
发现在进行对象的深度复制。看上去代码也没什么问题。但和同事一沟通,他将传感器采集到最近25分钟数据,都进行了一个Clone。这么说一还可能就是问题了。我们传感器平均1秒钟4000条数据,25分钟有高达600W条数据,再对600W的对象进行一个深度复制,就将产生1200W的对象。可想内存开销还是可观的。由于外层逻辑也是定时分析,分析完成后也没有进行GC的清理。程序运行时长了,内存就上去了。
四、分析Cpu占用高的情况
4.1 通过!t -special 命令,查看是否存在GC加收的情况
4.2 转换到2b04线程,查看调用栈
从上述调用栈可以看出来,在进行反序列化的时候,触发的GC回收。
4.3 通过syncblk,查看是否存在锁的情况
从上述信息可以看出,当前存在一个锁。
也可以看出,正常在等等GC回收的完成。GC算是CPU密集信息操作,又回收大量数据,CPU上去也算是正常。
五、总结
1 小对象,数量多的情况下,进行深度复制,会导致内存爆高
2 GC在回收大量对象时,会导致CPU爆高