虚拟机结构-运行时数据区

虚拟机结构-运行时数据区

 

程序计数器(Program Counter Register

程序计数器是一个记录着当前线程所执行的字节码的行号指示器。这个内存区域有以下特点:

1. 线程隔离性,每个线程工作时都有属于自己的独立计数器;
2. 执行 java 方法时,程序计数器是有值的,且记录的是正在执行的字节码指令的地址;
3. 执行 native 本地方法时,程序计数器的值为空( Undefined )。因为 native 方法是 java 通过 JNI 直接调用本地 C/C++ 库,可以近似的认为 native 方法相当于 C/C++ 暴露给 java 的一个接口, java 通过调用这个接口从而调用到 C/C++ 方法。由于该方法是通过 C/C++ 而不是 java 进行实现。那么自然无法产生相应的字节码,并且 C/C++ 执行时的内存分配是由自己语言决定的,而不是由 JVM 决定的;
4. 程序计数器占用内存很小,在进行 JVM 内存计算时,可以忽略不计;
5. 程序计数器,是唯一一个在 java 虚拟机规范中没有规定任何 OutOfMemoryError 的区域;
 

Java虚拟机栈Program Counter Register)和本地方法栈

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧用于存储局部变量、操作数栈、动态连接、方法出口等信息。本地方法栈和虚拟机栈比较相似,区别是虚拟机栈执行Java方法,本地方法栈为虚拟机使用到的Native方法服务。这个内存区域有以下特点:

线程隔离性;
这个区域会出现两种异常情况:
StackOverflowError:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError;
如果虚拟机栈可以动态扩展,扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常;
 

方法区(Method Area

方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区也叫Non-Heap(非堆),在HotSpot虚拟机上,很多人也将方法区成为“永久代(Permanent Generation)”,原因是这个区域大部分情况下不会进行GC,即使对这个区域做了GC,回收的空间也很少。方法区中还有一个运行时常量池,用于存放编译期生成的各种字面量和符号引用。方法区域的特点如下:

1. 线程共享;
2. 当方法区无法满足内存分配需求时,将抛出 OutOfMemoryError 异常,比如 PermGen space Metaspace
 

Java堆内存(Java Heap

Java堆是虚拟机中最大的一块内存,虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例。堆内存区域可以是固定大小的(通过-Xmx-Xms指定),也可以是动态扩展的。堆内存的特点有:

1. 线程共享;
2. 垃圾收集的主要区域,所以 Java 堆也成称为“ GC 堆” ;
3. 如果堆中没有内存分配给实例,并且也无法扩展时,会抛出 OutOfMemoryError 异常: Java heap space

 

直接内存

直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是会被频繁使用。NIONew input/output)是JDK1.4中新加入的类,引入了一种基于通道(channel)和缓冲区(buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过堆上的DirectByteBuffer对象对这块内存进行引用和操作。一般不会设置直接内存的大小,当各个区域内存总和大于物理内存时会出现OutOfMemoryError异常