import java.io.IOException;
public class JmapTest {
public static void main(String[] args) throws IOException {
System.out.println(111);
System.in.read();//阻塞进程来分析堆栈信息
}
}
jps找到进程号
把堆栈信息打出来,会在当前目录下生成文件
jmap -dump:live,format=b,file=heap1.hprof 8976
Heap dump file created
查看类加载器
jmap -clsstats 8976
查看class名
jmap -histo 8976|head -n 10
从打印结果可看出,类名中存在[C、[B等内容,
只知道它占用了那么大的内存,但不知道由什么对象创建的。下一步需要将其他dump出来,使用内存分析工具进一步明确它是由谁引用的、由什么对象
#instance 是对象的实例个数
#bytes 是总占用的字节数
class name 对应的就是 Class 文件里的 class 的标识
B 代表 byte
C 代表 char
D 代表 double
F 代表 float
I 代表 int
J 代表 long
Z 代表 boolean
前边有 [ 代表数组, [I 就相当于 int[]
对象用 [L+ 类名表示
该命令通常用来分析内存泄漏OOM,通常做法是:
1)首先配置JVM启动参数,让JVM在遇到OutOfMemoryError时自动生成Dump文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path
2)然后使用命令
jmap -dump:format=b,file=/path/heap.bin 进程ID
如果只dump heap中的存活对象,则加上选项-live。
性能问题分析思路
1、发现问题
1)、使用uptime命令查看CPU的Load情况,Load越高说明问题越严重;
系统负载请查看阮一峰的博客(https://ruanyifeng.com/blog/2011/07/linux_load_average_explained.html)
2)、使用jstat查看FGC发生的频率及FGC所花费的时间,FGC发生的频率越快、花费的时间越高,问题越严重;
2、导出数据:在应用快要发生FGC的时候把堆导出来
1)、查看快要发生FGC使用命令:
这个命令在window平台下受限制,只能在linux平台上面用
jmap -heap <pid>
或者
jhsdb jmap --pid 8976
3、通过命令查看大对象
也是使用jmap的命令,只不过参数使用-histo
使用:jmap -histo <pid>|less
可得到如下包含对象序号、某个对象示例数、当前对象所占内存的大小、当前对象的全限定名,如下图:
查看对象数最多的对象,并按降序排序输出:
执行:jmap -histo <pid>|grep alibaba|sort -k 2 -g -r|less
结果如图:
查看占用内存最多的最象,并按降序排序输出:
执行:jmap -histo <pid>|grep alibaba|sort -k 3 -g -r|less
jmap -dump:live,format=b,file=heap1.hprof 8976
直接生成hprof后缀的dump文件拖到jprofier工具里面查看大对象更加的方便
4、数据分析
总结
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。
4.使用jmap -histo:[live]查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。
5.也可以使用 jmap -dump:format=b,file=<fileName>命令将堆信息保存到一个文件中,再借助jhat命令查看详细内容
6.在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,把内存文件进行编号归档,便于后续内存整理分析。
7.在用cms gc的情况下,执行jmap -heap有些时候会导致进程变T,因此强烈建议别执行这个命令,如果想获取内存目前每个区域的使用状况,可通过jstat -gc或jstat -gccapacity来拿到。