【JVM】内存区域

657 阅读4分钟

Java 虚拟机将它所管理的内存划分为多个数据区域,分别有程序计数器、虚拟机栈、本地方法栈、堆、方法区、运行期常量池等。另外,这些区域也可以从线程是否共享的角度来进行分析。

image.png

1. 程序计数器(Promgram Counter Register)

字节码解释器工作时,通过程序计数器来获取下一条要执行的字节码指令、进行异常处理、线程恢复等。

内容:

  • 字节码指令的地址,当线程正在执行的是一个 Java 方法时,计数器中记录正在执行的虚拟机字节码指令的地址
  • 空(Undefined)

特点:

  • 线程私有,生命周期与线程相同。
  • 每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响。
  • 唯一一个没有规定任何 OutOfMemoryError 的内存区域

异常:

2. Java 虚拟机栈(Java Virtual Machine Stack)

描述 Java 方法执行的线程内存模型:每个方法被执行时,Java 虚拟机都会同步创建一个栈桢(Stack Frame)用户存储局部变量表、操作数栈、动态连接、方法出口等信息。

内容:

  • 8 种基本数据类型:boolean、byte、char、short、int、float、long、double
  • 对象引用(reference 类型),指向对象起始地址的引用指针、指向一个代表对象的句柄或其他与此对象相关的位置等
  • returnAddress 类型,指向一条字节码指令的地址

特点:

  • 线程私有,生命周期与线程相同
  • 一个方法被调用到执行完的过程,对应着一个栈桢在虚拟机栈中从入栈到出栈的过程。

异常:

  • 栈深度溢出:StackOverflowError 异常,线程请求的栈深度大于虚拟机所允许的深度
  • 栈扩展失败:OutOfMemoryError 异常,如果 Java 虚拟机栈容量可以动态扩展,则当栈扩展时无法申请到足够内存时会出现该异常

局部变量槽(Slot): 局部变量表中的存储空间以局部变量槽来表示,1 个变量槽实际占用的内存空间大小由具体虚拟机决定。

  • long、double 类型的数据占用两个变量槽,其余数据类型只占用一个。
  • 局部变量表所需的内存空间在编译期间完成分配。

3. 本地方法栈(Native Method Stacks)

与虚拟机栈的作用很相似,区别在于

  • 虚拟机栈:为虚拟机执行 Java 方法(也就是字节码)服务
  • 本地方法栈:为虚拟机使用到的本地方法服务

内容:

特点: 虚拟机可以根据需要自由实现本地方法栈,甚至可以将本地方法栈和虚拟机栈合二为一(如:Hot-Spot 虚拟机 )。

异常:(同 Java 虚拟机栈)

  • 栈深度溢出
  • 栈扩展失败

4. Java 堆(Java Heap)

虚拟机管理的内存最大的一块区域,在虚拟机启动时创建,该区域的唯一目的就是存放对象实例。

内容: 对象实例 特点: 虚拟机管理的内存最大的一块区域 异常:

5. 方法区(Method Area)

用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

内容: 已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

特点: 也被描述为堆的一个逻辑部分,亦称“非堆”(Non-Heap)为了与 Java 堆区分开。

异常: OutOfMemoryError 异常,方法区无法满足新的内存分配需求

该区域的内存回收,主要是针对常量池的回收和对类型的卸载,不过该区域的回收效果比较难令人满意。

6. 运行时常量池(Runtime Constant Pool)

是方法区的一部分,用于存放类在编译期生成的各种字面量与符号(类加载后放入常量池),一般也会把由符号引用翻译出来的直接引用也存储在运行时常量池。

内容: 类在编译期生成的各种字面量与符号(类加载后放入常量池)。

特点:

  • 与 Class 文件常量池的一个特征是具备动态性,运行期间也可以将新的常量放入池中,如 String 类的 intern() 。
  • 运行时常量池是方法区的一部分,所以也受到方法区内存的限制

异常: OutOfMemoryError 异常

Class 文件常量池

7. 直接内存(Direct Memory)

在 JDK1.4 中新加入的 NIO,可以通过 native 函数直接分配堆外内存,因为避免了在 Java 堆和 Native 堆中来回复制数据,所以在一定场景下可以提高性能。

内容: Java 堆中 DirectByteBuffer 对象保存了对该内存的引用。

特点: 不受 Java 堆大小的限制,但是受本机总内存大小以及物理器寻址空间的限制。

异常: OutOfMemoryError 异常,动态扩展时出现。

Direct Memory 不是虚拟机规范中的内存区域,但是这部分内存也被频繁使用,且也可能导致 OutOfMemoryError 异常。