1.常见参数配置
-XX:+PrintGC
每次触发GC的时候打印相关日志
-XX:+UseSerialGC
串行回收
-XX:+PrintGCDetails
更详细的GC日志
-Xms
堆初始值
-Xmx
堆最大可用值
-Xmn
新生代堆最大可用值
-XX:SurvivorRatio
用来设置新生代中eden空间和from/to空间的比例.
-XX:NewRatio
配置新生代与老年代占比 1:2
含以-XX:SurvivorRatio=eden/from=den/to
总结:在实际工作中,我们可以直接将初始的堆大小与最大堆大小相等,这样的好处是可以减少程序运行时垃圾回收次数,从而提高效率。否则初始值为0,程序开始运行就会有gc产生。
2.堆内存大小配置
使用示例: -Xmx20m -Xms5m
说明: 当下Java应用最大可用内存为20M, 初始内存为5M
// byte[] b = new byte[4 * 1024 * 1024];
// System.out.println("分配了4M空间给数组");
System.out.print("最大内存");
System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");
System.out.print("可用内存");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");
System.out.print("已经使用内存");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
程序运行前后可用内存增加了大约4M,如果使用byte[] b = new byte[25 * 1024 * 1024]
分配25M内存,那么会出现内存异常的异常。
3.设置新生代参数
使用示例:-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
说明:堆内存初始化值20m,堆内存最大值20m,新生代最大值可用1m,eden空间和from/to空间的比例为2/1
byte[] b = null;
for (int i = 0; i < 10; i++) {
b = new byte[1 * 1024 * 1024];
}
运行程序:eden:from:to = 2:1:1,可以看到内存不足,控制台第一行打印GC日志。因为可用的老年代内存是9M,新生代1M,所以程序GC。
4.新生代与老年代比例参数
使用示例: -Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=2
说明:堆内存初始化值20m,堆内存最大值20m,新生代最大值可用1m,eden空间和from/to空间的比例为2/1,新生代和老年代的占比为1/2
5. OutOfMemoryError
5.1 java堆内存溢出
错误原因: java.lang.OutOfMemoryError: Java heap space 堆内存溢出
解决办法:设置堆内存大小
参数: -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
说明:初始堆大小为1M,最大堆是10M
// -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
List<Object> listObject = new ArrayList<>();
for (int i = 0; i < 10; i++) {
System.out.println("i:" + i);
Byte[] bytes = new Byte[1 * 1024 * 1024];
listObject.add(bytes);
}
System.out.println("添加成功...");
5.2 虚拟机栈溢出
错误原因: java.lang.StackOverflowError 栈内存溢出
栈溢出 产生于递归调用,循环遍历是不会的,但是循环方法里面产生递归调用, 也会发生栈溢出。
解决办法:设置线程最大调用深度
-Xss5m
设置栈内存为5M,增大这个参数可以最大调节递归的深度
public class JvmDemo04 {
private static int count;
public static void count(){
try {
count++;
count();
} catch (Throwable e) {
System.out.println("最大深度:"+count);
e.printStackTrace();
}
}
public static void main(String[] args) {
count();
}
}
5.3 内存溢出与内存泄漏区别
Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内存资源耗尽);
Java内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
内存溢出,这个好理解,说明存储空间不够大。就像倒水倒多了,从杯子上面溢出了来了一样。
内存泄漏,原理是,使用过的内存空间没有被及时释放,长时间占用内存,最终导致内存空间不足,而出现内存溢出。