JVM堆参数调优和MAT工具
一丶. 堆参数调优入门
均以JDK1.8+HotSpot为例
jdk1.7:
jdk1.8:
3.2.1. 常用JVM参数
怎么对jvm进行调优?通过参数配置
参数 | 备注 |
---|---|
-Xms | 初始堆大小。只要启动,就占用的堆大小,默认是内存的1/64 |
-Xmx | 最大堆大小。默认是内存的1/4 |
-Xmn | 新生区堆大小 |
-XX:+PrintGCDetails | 输出详细的GC处理日志 |
java代码查看jvm堆的默认值大小:
Runtime.getRuntime().maxMemory() // 堆的最大值,默认是内存的1/4
Runtime.getRuntime().totalMemory() // 堆的当前总大小,默认是内存的1/64
3.2.2. 怎么设置JVM参数
程序运行时,可以给该程序设置jvm参数,不同的工具设置方式不同。
如果是命令行运行:
java -Xmx50m -Xms10m HeapDemo
eclipse 运行的设置方式如下:
idea运行时设置方式如下:
3.2.3. 查看堆内存详情
public class Demo2 {
public static void main(String[] args) {
System.out.print("最大堆大小:");
System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");
System.out.print("当前堆大小:");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
System.out.println("==================================================");
byte[] b = null;
for (int i = 0; i < 10; i++) {
b = new byte[1 * 1024 * 1024];
}
}
}
执行前配置参数:-Xmx50m -Xms30m -XX:+PrintGCDetails
执行:看到如下信息
新生代和老年代的堆大小之和是Runtime.getRuntime().totalMemory()
3.2.4. GC演示
public class HeapDemo {
public static void main(String args[]) {
System.out.println("=====================Begin=========================");
System.out.print("最大堆大小:Xmx=");
System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");
System.out.print("剩余堆大小:free mem=");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");
System.out.print("当前堆大小:total mem=");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
System.out.println("==================First Allocated===================");
byte[] b1 = new byte[5 * 1024 * 1024];
System.out.println("5MB array allocated");
System.out.print("剩余堆大小:free mem=");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");
System.out.print("当前堆大小:total mem=");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
System.out.println("=================Second Allocated===================");
byte[] b2 = new byte[10 * 1024 * 1024];
System.out.println("10MB array allocated");
System.out.print("剩余堆大小:free mem=");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");
System.out.print("当前堆大小:total mem=");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
System.out.println("=====================OOM=========================");
System.out.println("OOM!!!");
System.gc();
byte[] b3 = new byte[40 * 1024 * 1024];
}
}
jvm参数设置成最大堆内存100M,当前堆内存10M:-Xmx100m -Xms10m -XX:+PrintGCDetails
再次运行,可以看到minor GC和full GC日志:
3.2.5. OOM演示
把上面案例中的jvm参数改成最大堆内存设置成50M,当前堆内存设置成10M,执行测试: -Xmx50m -Xms10m
=====================Begin=========================
剩余堆大小:free mem=8.186859130859375M
当前堆大小:total mem=9.5M
=================First Allocated=====================
5MB array allocated
剩余堆大小:free mem=3.1868438720703125M
当前堆大小:total mem=9.5M
================Second Allocated====================
10MB array allocated
剩余堆大小:free mem=3.68682861328125M
当前堆大小:total mem=20.0M
=====================OOM=========================
OOM!!!
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.atguigu.demo.HeapDemo.main(HeapDemo.java:40)
实际开发中怎么定位这种错误信息?MAT工具
3.3. MAT工具
安装方式:eclipse插件市场下载
3.3.1. MAT工具的使用
运行参Leak Suspects数:-Xmx30m -Xms10m -XX:+HeapDumpOnOutOfMemoryError
重新刷新项目:看到dump文件
打开:
Actions: 介绍
Histogram:是我们使用最多的一个,可以列出内存中的对象,对象的个数及其大小
Class Name : 类名称,java类名
Objects : 类的对象的数量,这个对象被创建了多少个
Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用
Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收到内存的总和
Leak Suspects: 介绍
自动分析内存内存泄漏的原因,可以直接定位到Class,且行数。
1.2 idea分析dump文件
把上例中运行参数改成:
-Xmx50m -Xms10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\tmp
-XX:HeapDumpPath:生成dump文件路径。
再次执行:生成D:\tmp\java_pid20328.hprof文件
生成的这个文件怎么打开?jdk自带了该类型文件的解读工具:jvisualvm.exe
双击打开:
文件–>装入–>选择要打开的文件即可
装入后: