深入理解 java 虚拟机
文章目录


2.2 运行时数据区域

Java 虚拟机对内存的划分采用了分区的思想。

  • 线程共享
    • 方法区(Method Area)
    • 堆(Heap)
  • 线程私有
    • 虚拟机栈(VM Stack)
    • 本地方法站(Native Method Stack)
    • 程序计数器(Program Counter Register)

2.2.1 程序计数器

多线程是通过线程间切换并分配处理器执行时间的方式实现的,为了线程切换后能恢复到正确的执行位置,每天线程都需要有一个独立的程序计数器。

如果线程正在执行的是 Java 方法,那么 PC 记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,那么 PC 值为空。

此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。

2.2.2 Java 虚拟机栈

每个方法在执行是都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

每个方法的调用会返回的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

在 Java 虚拟机规范中,这这个区域规定了两种异常情况:StackOverflowError 和 OutOfMemoryError。

2.2.3 本地方法栈

本地方法栈与虚拟机栈类似,区别在于虚拟机栈为虚拟机执行 Java 方法(字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。

2.2.4 堆

此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。但由于JIT编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配在堆上也渐渐变得不是那么“绝对”了。

如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出 OutOfMemoryError 异常。

2.2.5 方法区

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

Java 虚拟机规范对方法区的限制非常宽松,除了和 Java 对一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。

当方法区无法满足内存分配需求时,将抛出 OutOfMemoryError 错误。

2.2.6 运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。用于存储编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池。

当常量池无法再申请到内存时会抛出 OutOfMemoryError 错误。

2.2.7 直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域。可能会抛出 OutOfMemoryError 错误。

在 JDK 1.4 中引入了 NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。

本文为原创文章,欢迎分享,勿全文转载,如果内容你实在喜欢,可以加入收藏夹,说不定哪天故事又继续更新了呢。
本文地址:https://qoogle.top/chapter-two-of-deep-understanding-of-java-virtual-machine/
最后修改日期:2020年6月12日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。