程序计数器能够看做是当前线程所执行的字节码的行号指示器 线程私有 异常: 惟一一个java虚拟机规范中没有规定任何OutOfMemoryError状况的区域
线程私有,生命周期和线程相同 虚拟机栈描述的是Java方法执行的内存模型:每一个方法在执行的同时会建立一个栈帧用于存储局部变量表、操做数栈、动态连接、方法出口等信息。局部变量表存放了编译期可知的各类基本数据类型、对象引用。 异常: 线程请求的栈深度大于虚拟机所容许的深度,将抛出StackOverFlowError异常 若是虚拟机栈能够动态扩展,若是扩展没法申请到足够的内存,就会抛出OOM
/** * 虚拟栈递归调用栈溢出(StackOverFlowError) * VM Args:-Xss512k */ public class JavaVMStackSOF { private int stackLenqth = 1; public void stackLeek() { stackLenqth++; //递归调用 stackLeek(); } public static void main(String[] args) { JavaVMStackSOF stackSOF = new JavaVMStackSOF(); stackSOF.stackLeek(); } } //结果 Exception in thread "main" java.lang.StackOverflowError at outofmemory.JavaVMStackSOF.stackLeek(JavaVMStackSOF.java:11)
/** * 建立线程致使OOM * VM Args: -Xss2M */ public class JavaVMStackOOM { private void dontStop(){ while (true){ } } public void stackLeakByThread(){ while (true){ Thread thread = new Thread(new Runnable() { public void run() { dontStop(); } }); thread.start(); } } public static void main(String[] args) { JavaVMStackOOM stackOOM = new JavaVMStackOOM(); stackOOM.stackLeakByThread(); } } //结果 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
全部线程共享 本地方法栈和Java虚拟栈类似,Java虚拟机栈为虚拟机执行Java方法(字节码)服务,本地方法栈为虚拟机 用到的native方法服务。 HotSpot虚拟机将虚拟机栈和本地方法栈合二为一
全部的对象实例和数组都要在堆上分配 Java堆是垃圾器管理的主要区域 异常: 堆中没有内存完成实例分配,而且堆没法在扩展的时,就会抛出OOM
/** * 堆内存溢出 * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError */ 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.OutOfMemoryError: Java heap space
全部线程共享 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据 异常: 方法区没法知足内存分配需求时,就会抛出OOM
方法区的一部分 用于存放编译期生成的各类字面量和符号引用 Java并不要求常量必定要是编译期才能产生,运行期间也可能将新的常量放入池中,好比String类的intern()方法 异常: 运行时常量池做为方法区的一部分,天然收到方法去内存的限制,常量池没法申请到内存抛出OOM
/** * 运行是常量池溢出 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M */ public class RuntimeConstantPoolOOM { public static void main(String[] args) { List<String> stringList = new ArrayList<String>(); int i = 1; while (true){ stringList.add(String.valueOf(i++)); } } } //结果 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.0发生如上错误,这个说明永久代已经在java8.0中被移除,被元空间替代。 关于为啥要移除替代本篇不累赘。若是使用的jdk8.0一下版本则会出现OOM:PermGen space 这样能够证实常量池属于方法区 //VM Args:-XX:MaxMetaspaceSize=2M(这样设置元空间大小 )
直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域 NIO可使用Native函数库直接分配堆外内存 异常: 本机内存不足抛出OOM
参考资料:《深刻理解Java虚拟机》java