JVM运行时数据区

1、什么是运行时数据区?

Java虚拟机在执行Java程序时,会把它管理的内存划分为若干不同的数据区域。这区域各有各的用途以及生命周期。

  1. 有的区域随着虚拟机的启动而一直存在。(线程共享)
  2. 有的区域则依赖用户线程的启动和结束分别创建和销毁。(线程私有)

JVM运行时数据区_第1张图片

2、程序计数器(Program Counter Register)

程序计数器可以看做当前线程执行的字节码的行数指示器。
不管是分支、循环、跳转等代码逻辑,字节码解释器在工作时就是改变程序计数器的值来决定下一条要执行的字节码。
每个线程都有一个独立的程序计数器。在任意一个确定的时刻,一个CPU内核都只会执行一条线程中的指令。
在Native方法,程序计数器的值是 Undefined
个人理解:有点像汇编语言的SS:SP,不过SS:SP总是指向下一个要执行的指令地址。

3、Java虚拟机栈(Java Virtual Machine Stack)

虚拟机栈也是线程私有的空间,生命周期与线程相同。
虚拟机栈描述了Java方法执行时的线程内存模型:每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧,用于储存:局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从被调用执行到执行完毕,都对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

局部变量表中存放了编译期可知的Java虚拟机基本数据类型、对象引用、返回地址(ReturnAddress)。
基本数据类型:byte、short、int、long、float、double、boolean、char。
对象引用:对象的起始地址 或 代表对象的句柄 或其他表示。
返回地址:一个字节码指令的地址。
这些数据类型在局部变量表中都以 **Slot局部变量槽** 的形式存储。其中 long 和 double 是64位长度,占用两个Slot,其余都只占用一个Slot。
局部变量表所需的空间在编译期就完成分配,所以进入一个方法时,栈帧中需要多大的局部变量空间是完全确定的。在运行期间不会改变局部变量表的大小(Slot数量)。

如果线程请求的栈深度,大于虚拟机最大允许的深度,虚拟机将抛出 StackOverFlowError 异常。
如果虚拟机栈容量允许动态扩展,栈申请时内存不够会抛出 OutOfMemoryError 异常。

4、本地方法栈(Native Method Stack)

本地方法栈与虚拟机栈所发挥的作用是非常相似的。
只不过虚拟机栈为虚拟机执行的Java方法(即字节码)服务,本地方法栈为虚拟机执行的本地方法(Native方法)服务。

与虚拟机栈一样,当栈深度溢出时,抛出 StackOverFlowError 异常。
当栈扩展内存不足时,抛出 OutOfMemoryError 异常。

5、Java堆(Java Heap)

Java堆是Java虚拟机所管理的内存最大的一块区域。Java堆是线程共享的,在虚拟机启动时创建。
Java堆存在的唯一目的就是 存放对象实例
几乎所有的对象实例都在这里分配内存。
Java堆是垃圾收集器管理的内存区域,有些资料称为GC堆。
Java堆在逻辑上应该认为是连续的,但是在具体的物理实现上,可以是不连续的。
Java堆可以是固定大小的,也可以是可扩展的。现在主流Java虚拟机都是可扩展的。

-Xmx 最大堆内存
-Xms 最小堆内存

如果Java堆没有足够的内存给分配实例,并且也无法继续扩展,则抛出 OutOfMemoryError 异常。

6、方法区(Method Area)

方法区也是线程共享的一片区域。用于存放被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码缓存等数据。

在JDK6以及之前,用永久代实现方法区。
在JDK7,将字符串常量池、静态变量移出方法区,放入Java堆。
在JDK8,废弃永久代,用本地内存中的元空间(Meta-Space)实现方法区。把JDK7中还剩余的内容,主要是类型信息放到元空间。

如果方法区没有足够内存时,会抛出 OutOfMemotyError 的异常。

你可能感兴趣的:(Java虚拟机,java)