JVM虚拟机实战案例 -- OOM

一、通过运行时验证Java虚拟机规范中描述的各个运行时区域存储的内容
二、在工作中遇到OOM,根据异常信息快速判断是哪个区域的内存溢出,知道什么样的代码可能导致OOM,以及解决方案

Java堆溢出

  1. VM参数: Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
    -XX:HeapDumpPath=D:\Java\dump2.hprof

  2. 代码

Map map = new HashMap<>();
for (long i = 0; i < Long.MAX_VALUE; i++) {
    map.put(i + "", i);
}
  1. 异常
    异常堆栈信息会报OutOFMemoryError,紧跟着进一步提示"Java Heap Space"

  2. 解决方案
    一般首先通过映像分析工具(MAT)对Dump出来的堆转存储快照进行分析
    JVM虚拟机实战案例 -- OOM_第1张图片

虚拟机栈和本地方法栈溢出

  • HotSpot并不分虚拟机和本地栈,栈容量由-Xss参数设置(递归最容易栈溢出)
  • 虚拟机栈描述了两种异常:
    1. 如果线程请求的的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError
    2. 如果虚拟机在扩展栈是无法申请到足够的内存空间,则抛出OoutofMemoryError
  1. VM参数:-Xss128k

  2. 代码

class JavaVMStackSOF{
    private  int stackLength=1;

    public void stackLeak(){
        stackLength++;
        stackLeak();
    }
}

JavaVMStackSOF javaVMStackSOF = new JavaVMStackSOF();
while (true){
    javaVMStackSOF.stackLeak();
}
  1. 异常信息
    Exception in thread “main” java.lang.StackOverflowError

  2. 异常信息
    JVM虚拟机实战案例 -- OOM_第2张图片

方法区和运行时常量池溢出()

  • 常量池是方法区的一部分(1.7之后会逐步去“永久代”,以下代码1.6之前)
  1. VM参数:-XX:PermSize=10M -XX:MaxPermSize=10M
  2. 代码
    while (true) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OOMObject.class);
        enhancer.setUseCache(false);
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object obj, Method method,
                                    Object[] args, MethodProxy proxy) throws Throwable {
                return proxy.invokeSuper(obj, args);
            }
        });
        enhancer.create();
    }
}

static class OOMObject {
}

本机直接内存溢出

  • DirectMemory容量通过-XX:MaxDirectMemorySize指定,如果不指定,默认与Java堆最大值(-Xmx)一样
  1. VM参数: -Xmx20M -XX:MaxDirectMemorySize=10M
  2. 代码
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class Dump {
    private static final int MB = 1024 * 1024;
    public static void main(String[] args) throws IllegalAccessException {
        
        Field field= Unsafe.class.getDeclaredFields()[0];
        field.setAccessible(true);
        Unsafe un= (Unsafe) field.get(null);
        while (true){
            un.allocateMemory(MB);
        }
	}
}
  1. 异常
    JVM虚拟机实战案例 -- OOM_第3张图片

你可能感兴趣的:(java)