Java应用内存泄漏/内存占用高问题分析

问题描述

===========

内存泄漏(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对象进行分析优化。

原文地址:https://www.cnblogs.com/wang-xiaohui/p/14644135.html