场景
JVM-常用工具(jps、jstat、jinfo、jmap、jhat、jstack、jconsole、jvisualvm)使用:
JVM-常用工具(jps、jstat、jinfo、jmap、jhat、jstack、jconsole、jvisualvm)使用_jvm分析工具-CSDN博客
上面讲了jmap的简单使用。
下面记录其常用功能,实现堆转储离线文件,并通过三方工具进行可视化查看和分析。
性能监控之常见 Java Heap Dump 方法
dump heap是诊断与内存相关的问题的重要手段,例如:内存泄漏、垃圾回收问题和java.lang.OutOfMemoryError。
同时也是优化内存消耗的重要手段。有非常多的工具可以dump heap,以及分析转储文件,
例如:visualVM、Eclipse MAT和 Heap Hero等等。
Windows上使用jmap实现手动堆转储到文件
jmap是jdk自带的工具,可以dump heap到文件。例如:
jmap-dump:format=b,file=/opt/tmp/heapdump.bin 37320
注意:
可以添加“live”选项,仅将内存中的活动对象写入堆转储文件。
如果未通过此选项,则所有对象,即使是准备好进行垃圾回收的对象也会打印在堆转储文件中。
它将大大增加堆转储文件的大小。这也将使分析变得乏味。
要解决内存问题或优化内存,仅需使用“ live”选项即可。
jmap-dump:live,format=b,file=myjmapfile.txt 19570
其中file跟的是堆转储文件的存放位置,如果是在windows上,则是形如
jmap-dump:live,format=b,file=D:\test\Jmap.hprof 18700
然后最后面是跟的pid,获取pid的方式可以通过
jps
实现
MAT(Memory Analyzer Tool)
Memory AnalyzerTool是一个快速且功能丰富的Java堆分析器,可帮助您查找内存泄漏并减少内存消耗。
使用Memory Analyzer分析具有数亿个对象的高效堆转储,快速计算对象的保留大小,查看谁阻止垃圾收集器收集对象,
运行报告以自动提取泄漏嫌疑者。
下载地址:
Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation
注意这里的MAT的版本与JDK的版本有对应要求,最新版的要求JDK17,这里使用的JDK1.8,所以下载1.10.0在windows上的安装包。
下载之后直接解压,双击MemoryAnalyzer.exe启动即可,启动之后可以看到下面有个Open a Heap Dump选项。
将上面保存的文件打开即可进行离线分析。
注:
实现
下面编写一个简单的测试代码进行演示以上工具的使用
下面以是否使用String的intern()方法占用内存消耗的对比为例
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class StringInternTest {
static final int MAX = 1000 * 10000;
static final String[] arr = new String[MAX];
public static void main(String[] args) throws InterruptedException {
Integer[] DB_DATA = new Integer[10];
Random random = new Random(10 * 10000);
for (int i = 0; i < DB_DATA.length; i++) {
DB_DATA[i] = random.nextInt();
}
long t = System.currentTimeMillis();
for (int i = 0; i < MAX; i++) {
arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length]));
//arr[i] = new String(String.valueOf(DB_DATA[i % DB_DATA.length])).intern();
}
System.out.println((System.currentTimeMillis() - t) + "ms");
System.gc();
TimeUnit.SECONDS.sleep(25);
}
}
首先是不使用intern方法,编写如上代码,最后面让线程休眠25的目的是可以获取到pid,并执行jmap的命令
运行以上main方法,然后打开cmd,输入
jps
获取到pid,等待输出耗时多少毫秒后,执行jmap指令
jmap-dump:live,format=b,file=D:\test\Jmap6.hprof 18700
这里的pid获取的是18700,然后将文件转储在D:\test\目录下,文件名叫做Jmap6.hprof
使用MAT打开上面的文件,Actions-Histogram
展示内存中的对象,对象的个数及大小。
Class Name : 类名称,java类名
Objects : 类的对象的数量,这个对象被创建了多少个
Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用
Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收到内存的总和;
比如这里查看java.lang.String类,其实例数为1000万个,内存消耗240多M。
把上面示例代码的使用intern()的放开,原先的注释掉,再次执行上面的流程,生成新的dump文件并分析
可以看到在使用了intern方法后示例数仅为7000个,且内存消耗为170K。