下图是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虚拟机》,如果有不对的地方请指正,谢谢