JVM: 1.0.0 运行时数据区域概念



1. 运行时数据区域概念概述

oracle 官方文档

JVM定义在程序执行期间使用的各种运行时数据区。 其中一些数据区域是在Java虚拟机启动时创建的,在JVM退出时才会被销毁。 其他数据区域是属于每个线程的,每个线程的数据区在创建线程时创建,并在线程退出时被销毁。

1) PC寄存器(program counter)

JVM可以同时支持许多线程在执行。 每个JVM线程都有自己的pc(程序计数器)寄存器。 在任何时候,每个JVM线程都会执行单个方法的代码,即该线程的当前方法。 如果该方法不是native的,则pc寄存器包含当前正在执行的JVM指令的地址。 如果线程当前正在执行的方法是native,那么JVM的pc寄存器的值是未定义的。Java虚拟机的pc寄存器足以在特定平台上保存returnAddress或本地指针。

2) JVM栈

每个JVM线程都有一个私有JVM栈,与线程同时创建。 一个JVM栈会存储frames。 Java虚拟机堆栈类似于诸如C的常规语言的堆栈:它保存局部变量和部分结果,并且在方法调用和返回中起作用。 因为Java虚拟机堆栈从来不被直接操作,除了push和pop frames,frames可以被堆分配。 JVM栈的内存不需要是连续的。

该规范允许JVM栈具有固定大小或者根据计算的需要动态地扩展和收缩。 如果JVM栈是固定大小的,则当创建该栈时,可以独立地选择每个JVM栈的大小。

JVM可以为程序员或用户提供对JVM栈初始大小的控制,以及在动态扩展或收缩Java虚拟机堆栈的情况下控制最大值和最小值。

以下异常与JVM栈相关:

总结栈的特点

3) JVM堆

在JVM中的堆(heap)被JVM线程所共享,堆是一个JVM的运行时数据区域,从中可以给类实例和数组分配内存。当JVM启动时创建堆内存区域,object的堆存储由自动存储管理系统(称为垃圾收集器)回收;object不会显式的释放内存。

以下异常条件与堆相关联:

总结堆的特点

4) JVM方法区(永久代)

JVM具有在所有JVM线程之间共享的方法区。方法区类似于用于操作系统过程中的常规语言的编译代码或类似于“text”段的存储区域。它存储per-class结构,如运行时常量池,字段和方法数据,以及方法和构造函数的代码,包括在类和实例初始化和接口初始化中使用的特殊方法。

方法区在JVM启动时创建。虽然方法区在逻辑上是堆的一部分,但一般简单的情况下可能选择不对其进行垃圾回收或压缩它。本规范不强制用于管理编译代码的方法区域或策略的位置。方法区可以具有固定大小,或者可以根据计算的需要进行扩展,并且如果不需要更大的方法区,则可以收缩。方法区的内存不需要是连续的。

JVM实现可以为程序员或用户提供对方法区域的初始大小的控制,以及在变化大小的方法区的情况下,控制最大值和最小值。

以下异常条件与方法区域相关联:

总结方法区的特点

方法区是一种jvm规范,永久代是hotspot虚拟机(oracle jdk都是这种虚拟机)对方法区的一种实现,从jdk7中,oracle就已经开始了永久代的取消工作,更是在jdk8中,彻底使用元空间来替代了永久代。

取消持久代的很主要的一个原因是,持久代使用的是java heap,在动态生成类时,永久代分配空间不足,无法满足类信息的储存需要,报出内存溢出错误。 而元空间直接使用的是native heap,也就是说直接试用了系统的内存,因此,默认情况下,元空间的大小只受到系统内存的限制,当然,我们也可以通过jvm -XX:指定参数的方式来限制它。
另外一个原因就是,持久代这东西只有hotspot虚拟机里面有,而BEA JRockit和IBM J9里面并没有这样一个概念,而oracle收购了BEA JRockit,并且,想把hotspot和JRockit合并。

jvm对方法区的调优参数,从jdk7的永久代的限制参数更改为jdk8的元空间限制参数:

  • 永久代:
    • PermSize,初始化大小,默认是12M
    • MaxPermSize,最大容量,默认是64M
  • 元空间:
    • MetaspaceSize,初始化大小,默认会根据程序运行动态调整
    • MaxMetaspaceSize,最大容量,默认是系统内存上限

永久代与元空间的异同

5) JVM常量池

常量池是为了避免频繁的创建和销毁对象而影响系统性能而分配的一个内存区域。运行时常量池是在一个class文件中的constant_pool表的每个类或每个接口的运行时表示

总结常量池特点

6) JVM本地方法栈

JVM的实现可以使用俗称为“C栈”的常规栈来支持本地方法(以Java编程语言之外的语言编写的方法)。本地方法栈也可以通过在诸如C语言中实现用于JVM的指令集的解释器来使用。不能加载本地方法并且本身不依赖于常规栈的JVM实现不需要提供本地方法堆栈。如果提供,本地方法堆栈通常在每个线程创建时为每个线程分配。

该规范允许本地方法堆栈具有固定大小或者根据计算的需要动态地扩展和收缩。如果本地方法堆栈具有固定大小,则当创建该堆栈时,可以独立地选择每个本地方法堆栈的大小。 JVM实现可以为程序员或用户提供对本地方法栈的初始大小的控制,以及在变化大小的本地方法栈的情况下,控制最大和最小方法栈大小。

以下异常条件与本机方法堆栈相关联: