程序计数器(pc计数器)
线程私有,唯一一个没有OutOfMemoryError。JVM的多线程是通过线程轮流切换并分配处理器执行时间来实现的,为了线程切换后能恢复到正确的执行位置,每个线程都有一个独立的pc计数器。
线程正执行一个java方法,则记录的是正执行的字节码指令的地址;native方法,则此时计数器值为空。
虚拟机栈(VM Stack)
线程私有,描述的是java方法执行的内存模型,每个方法在执行的同时创建一个栈帧(Stack Frame)用于存储 局部变量表、操作数栈、动态链接、方法出口 等信息。方法调用直至执行完成的过程,对应一个栈帧入栈到出栈的过程。
局部变量表所需空间在编译期间就确定,方法运行时不会改变。存放了方法中的 基本类型、对象引用和returnAddress类型(指向一条字节码指令的地址)。其中64位长度的long和double会占用2个局部变量空间。
若是不可扩展的,如果线程请求的栈深度大于虚拟机所允许,则抛StackOverflowError
若是可扩展的,申请不到足够的内存,则抛OutOfMemoryError。
本地方法栈(Native Method Stack)
与虚拟机栈很相似,虚拟机栈面向java方法,这个面向native方法。同样是那两种异常。
java堆(Java Heap)
线程共享。虚拟机启动时创建,用于存放对象实例和数组,物理上空间可以不连续,可以实现成固定大小的,也可以是可扩展的,是垃圾收集器管理的主要区域。没有内存了就抛OutOfMemoryError。
数组是引用类型,它的引用在栈里的对应方法的局部变量表中。
方法区(Method Area)
线程共享。存放JVM加载的 类信息、常量、静态变量、即时编译器编译后的代码 等数据。物理空间可不连续,可固定大小,也可是可扩展的,内存回收主要针对常量池的回收和类型的卸载。OutOfMemoryError。
运行时常量池(Runtime Constant Pool)是方法区一部分,用于存放class文件中的字面量和符号引用,还有翻译出的直接引用。具备动态性,运行时也可以放入新的常量,常用的是String类的intern()方法。
直接内存(Direct Memory)
并不是运行时数据区的一部分。
OutOfMemoryError
JDK1.4中加入了NIO类,引入了一种基于通道与缓冲区的I/O方式,可以使用Native库函数直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免的在java堆和Native堆中来回复制数据。