JVM 运行时数据区
1 .运行时数据区组成概述
JVM 的运行时数据区,不同虚拟机实现可能略微有所不同,但都会遵从 Java 虚拟机规范,Java 8 虚拟机规范规定,Java 虚拟机所管理的内存将会包括以下几个运行时数据区域:
2.程序计数器
1.概述
JVM 中的程序计数寄存器(Program Counter Register)中的 Register 命名源于CPU 的寄存器,寄存器存储指令相关的现场信息.CPU 只有把数据装载到寄存器才能运行. 这里,并非是广义上所指的物理寄存器,或许将其翻译为 PC 计数器(或指令计数器)会更加贴切(也称为程序钩子),并且也不容易引起一些不必要的误会.JVM 中的PC 寄存器是对物理 PC 寄存器的一种抽象模拟.
2.作用
程序计数器用来存储下一条指令的地址,也即将要执行的指令代码.由执行引擎读取下一条指令.
-
它是一块很小的内存空间,几乎可以忽略不计,也是运行速度最快的存储区域.
-
在 JVM 规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程生命周期保持一致.
-
任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法.程序计数器会存储当前线程正在执行的Java方法的JVM指令地址.如果是在执行native方法,则是未指定值(undefined).
-
它是程序控制流的指示器,分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器来完成.
-
字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令.
-
它是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域.
3. Java 虚拟机栈
1.背景
由于跨平台性的设计,Java 的指令都是根据栈来设计的.不同平台CPU 架构不同,所以不能设计为基于寄存器的.基于栈的指令设计优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样功能需要更过的指令集.
2.栈和堆的区别
栈是运行时的单位,堆是存储时的单位
栈解决的是程序的运行问题 即程序如何处理数据
堆解决的是程序的存储问题 即数据放在哪,怎么放
3. Java 虚拟机栈是什么?
-
Java 虚拟机栈(Java Virtual Machine Stack),早期也叫 Java 栈.
-
每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个栈帧,对应着一次方法的调用.
-
Java 虚拟机栈是线程私有的.
-
生命周期和线程一致.
4.作用
主管 Java 程序的运行,它保存方法的局部变量(8 种基本数据类型,对象的引用地址),部分结果,并参与方法的调用和返回.
5.特点
-
栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器.
-
JVM 直接对 java 栈的操作只有两个:调用方法进栈. 执行结束后出栈.
-
不存在垃圾回收问题
6.栈中存储什么
-
每个线程都有自己的栈,栈中的数据都以栈帧为单位存储.
-
在这个线程上正在执行的每个方法都各自对应一个栈帧.
-
栈帧是一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息.
7.栈的运行原理
- JVM 直接对 java 栈的操作只有两个,就是对栈帧的进栈和出栈,遵循”先进后
出”/后进先出的原则. - 只有当前在执行的方法的栈帧(栈顶)是有效地,这个栈帧被称为当前栈,与当前栈帧对应的方法称为当前方法,定义这个方法的类称为当前类.
- 执行引擎中的指令只针对当前栈进行操作
- 如果该方法调用了其他方法,那么对应的新的栈帧就会被创建,成为当前栈帧.
**注:**不能在栈中引用其他栈帧(方法)
Java 方法有两种返回的方式,一种是正常的函数返回,使用 return 指令,另一种是抛出异常.不管哪种方式,都会导致栈帧被弹出.
8.栈帧的内部结构
每个栈帧中存储着:
- 局部变量表(Local Variables)
局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。 - 操作数栈(Operand Stack)(或表达式栈)
栈最典型的一个应用就是用来对表达式求值。在一个线程执行方法的过程中,实际上就是不断执行语句的过程,而归根到底就是进行计算的过程。因此可以这么说,程序中的所有计算过程都是在借助于操作数栈来完成的。 - 动态链接(Dynamic Linking) (或指向运行时常量池的方法引用)
因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。 - 方法返回地址(Retuen Address)(或方法正常退出或者异常退出的定义)
当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。
9.本地方法栈
- 虚拟机管理 java 方法的调用,而本地方法栈用于管理本地方法的调用
- 本地方法栈是私有的
- 本地方法栈是用C语言写的
- 它的具体做法是在 Native Method Stack 中登记 native 方法,在Execution Engine 执行时加载本地方法库.
- 允许被实现成固定或者是可动态扩展的内存大小.内存溢出方面也是相同的