下图是JVM运行时将内存划分的几个区域,后面总结一下几个区域的内存溢出情况
虚拟机栈:线程私有,用于存储局部变量、操作数栈、动态链接、方法出口等信息
本地方法栈:线程私有,用于JVM执行Native方法时使用
程序计数器:线程私有,是一块较小的内存空间,可以看做是当前线程执行的字节码指示器
方法区:线程共享,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
堆:线程共享,存储对象实例。
在JDK8后,已经取消了方法区,而是把这些数据存到了元空间(MetaSpace)中,元空间直接使用本地内存
元空间内存溢出 如果在JDK8中使用-XX:PermSize=10m -XX:MaxPermSize=10m 配置VM内存,会得到如下提示
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10m; support was removed in 8.0
JDK8已经不存在方法区,而变成了元空间,元空间大小配置 -XX:MetaspaceSize,初始空间大小 -XX:MaxMetaspaceSize,最大空间 将VM配置改为-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m,重新运行出现内存溢出
java.lang.OutOfMemoryError: Metaspace
测试用例
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author: jujun chen
* @description: 使用了CGLIB来动态生成类,-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
* @date: 2019/4/7
*/
public class JavaMetaSpaceOOM {
static class OOMObject{}
public static void main(final String[] args) {
while (true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o,objects);
}
});
enhancer.create();
}
}
}
堆内存溢出
java.lang.OutOfMemoryError: Java heap space 这是碰到次数最多的溢出
测试用例VM配置为 -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError 可以在虚拟机内存溢出时Dump出当前内存堆,该文件可以用Eclipse Memory Analyzer,或者IDEA JProfiler分析
import java.util.ArrayList;
import java.util.List;
/**
* @author: jujun chen
* @description: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
* @date: 2019/4/7
*/
public class HeapOOM {
static class OOMObject{}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while (true){
list.add(new OOMObject());
}
}
}
虚拟机栈和本地方法栈溢出
Exception in thread "main" java.lang.StackOverflowError
测试用例VM配置为 -Xss160k
/**
* @author: jujun chen
* @description: -Xss160k
* @date: 2019/4/7
*/
public class VMStackSOF {
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args) {
VMStackSOF oom = new VMStackSOF();
oom.stackLeak();
}
}
参考《深入理解Java虚拟机》