问题描述
===========
内存泄漏(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。
GSCloud产品中,真正的内存泄漏比较少,通常出现较多的问题是内存占用高的问题,二者分析思路相同。
故障排查
===========
整体思路:明确出现泄漏的class,结合coredump、线程堆栈等进一步确认业务场景。
跟踪步骤:
(1)JProfiler跟踪内存对象信息
①选择Telemetries-Memory即可查看内存整体占用情况。
②选择Live memory-All objects可查看当前时刻内存对象统计信息。
③点击Mark Current可以创建当前时刻内存对象基线,且可以查看两次Mark期间对象的变化情况。
首次mark
第二次mark
(2)JDK内置的jcmd工具收集内存堆直方图
通过JDK内置的jcmd工具定期获取内存增长过程中的内存堆直方图,通过对比内存堆直方图Class的变化,确认泄漏的class。通常,为了便于定位涉及的功能场景,在抓取内存直方图时通常一并收集线程快照。收集内存堆直方图并保存到日志文件的命令:jcmd PID GC.class_histogram >>tracelog.log,收集线程堆栈快照的命令:jcmd PID Thread.print >>tracelog.log。
为了操作方便,整理了批量脚本,按照如下步骤操作即可收集内存及线程信息。
① 将troubleshooting.sh文件放到JDK的bin目录下,JDK所在路径为*/jstack/runtime/java/x86_64-linux/bin
②将troubleshooting.sh授予可执行权限:chmod +x troubleshooting.sh
③运行troubleshooting.sh抓取堆栈信息:./troubleshooting.sh 。执行后在jdk bin目录下会产生一个命名为trace.log的日志文件,trace.log默认只保存最近一次抓取的日志内容。
④通过 sz trace.log命令或其他文件传输工具将日志文件下载到本地查看即可。
troubleshooting.sh脚本信息如下:
rm -rf trace.log ; ./jcmd /jstack/runtime/caf-bootstrap.jar VM.uptime >>trace.log ; ./jcmd /jstack/runtime/caf-bootstrap.jar VM.flags >>trace.log ; #echo "Stack info" >>%filename% ; ./jcmd /jstack/runtime/caf-bootstrap.jar Thread.print >>trace.log ; #echo "memory objects info" >>trace.log ; ./jcmd /jstack/runtime/caf-bootstrap.jar GC.class_histogram -all >>trace.log ; #echo "heap info" >>trace.log ; ./jcmd /jstack/runtime/caf-bootstrap.jar GC.heap_info >>trace.log ;
解决方案
===========
相关功能开发针对持续增长的top对象进行分析优化。