JVM运行时数据区

JVM运行时数据区

JVM运行时数据区

一、堆

堆主要用来存放对象实例

  • Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。
  • 堆内存唯一的目的就是存放对象实例。
  • OutOfMemoryError异常时因为堆中已没有内存完成实例分配,并且堆也无法再扩展。

二、方法区(元空间)

方法区是各个线程共享的内存区域,它用于已被虚拟机加载的:

  • 类信息
  • 常量
  • 静态变量
  • 即时编译器编译后的代码等数据

垃圾收集行为很少出现在方法区,但并非数据进了方法区就永久的存在了,这个区域的内存回收目标主要针对常量池的回收和类的卸载,当方法区无法满足内存分配时将抛出OutOfMemoryError异常。

三、栈

Java栈是Java方法执行的内存模型每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程就对应一个栈帧在虚拟机中入栈和出栈的过程。

栈帧(Stack Frame)

栈帧由三部分组成:局部变量表、操作数栈和帧数据。
栈帧的大小因局部变量表和操作数栈而异。当JVM执行一个方法时,他会检查class中的数据,以便确定一个方法执行时在局部变量表和操作数栈中所需存储的word size。然后,JVM会为当前方法创建一个size相对应的栈帧,然后把它push到栈顶。
JVM运行时数据区
一个栈帧需要分配多少内存,在编译的时候已经确定,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机的实现。

局部变量表

Local Variable Table 用于保存函数的参数以及局部变量用的,局部变量表中的变量只在当前函数调用中有效,当函数调用结束后,随着函数栈帧的销毁,局部变量表也会随着销毁。局部变量表在编译期确定大小。

  • 在编译程序代码的时候就可以确定栈帧中需要多大的局部变量表,具体大小可在编译后的Class文件中看到
  • 局部变量表的容量以Variable Slot(变量槽)为最小单位,每个变量槽都可以存储32位的内存空间。
  • 在方法执行时,虚拟机使用局部变量表完成参数值到参数变量列表的传递过程的,如果执行的是实例方法,那局部变量表中第0位索引的Slot默认是用于传递方法所属对象实例的引用(在方法中可以通过关键字this来访问到这个隐含的参数)。
  • 其余参数则按照参数顺序排列,占用从1开始的局部变量Slot。
  • 基本类型数据以及引用和returnAddress(返回地址)占用一个变量槽,long和double需要两个。
    JVM运行时数据区

操作数栈

Operand Stack。主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。只支持出栈入栈操作。同样也可以在编译期确定大小。

  • 栈帧被创建时,操作数栈是空的。操作栈的每个项可以存放JVM的各个数据类型,其中long和double类型(64位数据)占用两个栈深。
  • 方法执行的过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是入栈和出栈操作。
  • 操作栈在在调用其他有返回结果的方法时,会把结果push到栈上(通过操作数栈来进行参数传递)。

动态链接

  • 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接。
  • 在类加载阶段中的解析阶段会将符号引用转为直接引用,这种转化也成为静态解析。另外的一部分将在运行是转化为直接引用,这部分称为动态链接。

返回地址

方法执行后,只有两种方式可以退出:方法返回指令、异常退出。

帧数据区

栈帧需要一些数据来支持常量池解析、正常方法返回和异常处理等。在帧数据去中保存着访问常量池的指针,方便程序访问常量池。帧数据区的大小依赖于JVM的具体实现。