JVM 运行时数据区

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

开局盗张图

6 JVM Runtime Data Areas

  • 程序计数器(Program Counter Register)

每个线程都有自己的程序计数器,并且任何时间一个线程都只有一个方法在执行。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址;如果是在执行本地方法,则是未指定值(undefned)。

  • Java虚拟机栈(Java Virtual Machine Stack)

每个线程在创建时都会创建一个虚拟机栈,存储栈帧(Stack Frame),一个方法调用会生成一个栈帧。JVM对虚拟机栈的直接操作只有压栈和出栈。每个栈帧中存储着局部变量表、操作数(operand)栈、动态链接、方法正常退出或者异常退出的定义等。java虚拟机栈可以追踪程序执行和记录stack trace。可以通过Xss参数设置线程栈大小。

如果堆栈大小超过设置最大值会引起StackOverflowError。

如果Java虚拟机堆栈可以动态扩展,并且尝试进行扩展,但没有足够的内存来进行扩展,或者没有足够的存储器来创建新线程的初始Java虚拟机栈,则Java虚拟机会抛出OutOfMemoryError

  • 堆(Heap)

堆是线程共享区域,用来存储Java对象实例,虚拟机启动时创建。几乎所有创建的Java对象实例都是被直接分配在堆上。堆中存储的对象实例通过垃圾收集器(garbage collector)自动回收,不会自动释放。堆内存不需要连续。堆可以是固定大小的,或者可以根据计算的需要进行扩展。可以通过-Xms设置初始堆大小,-Xmx设置最大堆大小。如果程序执行需要的堆比所能提供的堆多,Java虚拟机会抛出OutOfMemoryError。

  • 方法区(Method Area)

方法区也是所有线程共享的内存区域,用于存储所谓的元(Meta)数据,它存储每个类的结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括类和实例初始化以及接口初始化中使用的特殊方法。java8之前将方法区称为永久代(Permanent Generation)通过**-XX:PermSize**、-XX:MaxPermSize:分别设置永久代初始与最大值。JDK 8中将永久代移除,同时增加了元数据区(Metaspace),使用**-XX:MetaspaceSize**、-XX:MaxMetaspaceSize设置元空间初始值及最大值。如果方法区可使用内存不足也会抛出OutOfMemoryError。

  • 运行时常量池(Run-Time Constant Pool)

运行时常量池是方法区的一部分。运行时常量池是类文件中constant_pool表的每个类或每个接口的运行时表示。它包含多种常量,从编译时已知的数字文字到必须在运行时解析的方法和字段引用。运行时常量池的功能类似于传统编程语言的符号表。常量池可使用内存不足也会抛出OutOfMemoryError

  • 本地方法栈(Native Method Stack)

本地方法栈是每个线程独有的,支持对本地方法(native method)的调用。本地方法不是java语言编写,不会编译成字节码,因此需要不同的内存区域。本地方法栈和jvm方法栈很相似。本地方法栈的目的是为了追踪本地方法调用。

参考:

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

posted @ 2023-06-01 18:16  朋羽  阅读(11)  评论(0编辑  收藏  举报