Java 虚拟机内存构成

图1. Java 虚拟机运行时数据区

一、程序计数器

作用

当前线程所执行的字节码的行号指示器。

特点
  • 占用较小内存空间
  • 执行字节码的行号指示器
  • 线程独立
  • 不会产生空指针异常
  • 一个处理器(内核)只会执行一条线程的指令

二、虚拟机栈:

作用

描述 Java 方法(JVM 最基本执行单元)执行的线程内存模型。

栈帧

用于支持虚拟机进行方法调用和方法执行的数据结构。

栈帧构成
  • 局部变量表
    • 编译期可知的基本类型(boolean、byte、char、short、long、float、long、double)
    • 对象引用(reference 类型,非对象本身。可能是对象指向起始地址的引用指针,也可能是指向代表对象的句柄或其他与对象相关位置)
    • returnAddress 类型(指向了一个字节码指令地址)
  • 操作数栈
  • 动态连接
  • 方法出口
特点:
  • 线程私有
  • 生命周期与线程相同。
  • 每个方法创建时,同步创建一个栈帧。
  • 从方法调用到执行完毕,对应栈帧入栈到出栈全过程。
  • 局部变量表数据以局部变量槽来存储,64 位长度的 long 和 double 类型的数据占用两个变量槽,其余占用一个。在编译器已经分配好槽数量,方法执行时不会改变槽数量。
  • 会产生两种异常:
    1. 若线程请求深度大于虚拟机允许的深度,抛出 StackOverflowError 异常;
    2. 若 JVM 栈容量可扩展且扩展时无法申请到足够的内存则抛出 OutOfMemoryError 异常。

三、本地方法栈

特点
  • 与虚拟机栈功能类似,本地方法栈为本地(Native)方法服务。
  • 部分虚拟机中,虚拟机栈和本地方法栈合并在一起
  • 与虚拟机栈一样,会产生两种异常:
    1. 若线程请求深度大于虚拟机允许的深度,抛出 StackOverflowError 异常;
    2. 若 JVM 栈容量可扩展且扩展时无法申请到足够的内存则抛出 OutOfMemoryError 异常。

四、Java 堆

作用

几乎所有对象实例都是在这里分配内存。

特点
  • 虚拟机管理的内存中最大的一块内存区域
  • 物理内存可不连续,但是逻辑内存是连续的
  • 所有线程共享
  • 启动时由虚拟机创建
  • Java 堆没有内存完成实例分配,且无法扩展时,抛出 OutOfMemoryError 异常。

五、方法区

作用

存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。又叫做“非堆”。

特点
  • 物理内存可不连续,但是逻辑内存是连续的
  • 所有线程共享
  • 如果无法满足新的内存分配需要,抛出 OutOfMemoryError 异常。
运行时常量池
  • 作用:
    存放编译期生成的各种字面量与符号引用
  • 特点:
    • 属于方法区的一部分
    • 具备动态性,除了编译期产生外,运行期间也可以产生,例如:String.intern()
    • 不同提供商可按自己需要实现此区域

六、直接内存

特点
  • 不是虚拟机运行时数据区的一部分,不属于 Java 虚拟机规范中定义的内存区域
  • 不受 Java 堆内存大小的限制
  • 剩余物理或操作系统级的内存不足以完成直接内存分配,抛出 OutOfMemoryError 异常。
用途

JDK 1.4 中,NIO 引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,可直接使用Native函数直接分配堆外内存,并通过储存在 Java 堆里面的 DirectByteBuffer 对象作为这块内存的引用进行操作,避免了在 Java 堆和 Native 堆中来回复制数据,从而提升性能。

你可能感兴趣的:(Java 虚拟机内存构成)