JVM(三) -运行时数据区(Runtime Data Area)、栈帧(Frame)

Java运行时数据区

在这里插入图片描述
运行时数据区主要包括 JVM stacks 、PC寄存器(Program Counter Register)、方法区(Method Area)、本地方法栈(Native Method Stacks)、堆(Heap)。 Java 虚拟机定义了在程序执行期间使用的不同的运行时数据区。有些数据区是线程共享,有的则被线程独享。线程独享的数据区跟随线程的创建退出而创建销毁。直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁的使用,也可能会导致OOM(OutOfMemoryError)

线程共享的有堆和方法区,每个线程独享pc,虚拟机栈、本地方法栈

在这里插入图片描述

PC寄存器

PC:线程私有
先看一下官方文档当中的描述:
在这里插入图片描述
PC寄存器用来存储指向下一条指令的地址,也就是将要执行那一条指令。由执行引擎读取系一条指令。

1.是一块很小的内存空间,也是运行最快的存储区域
2.线程私有
3.只会记录当前线程正在执行Java代码的JVM指令地址。如果是native方法,则为空
4.Java虚拟机规范中,这是唯一一块没有OOM的区域。

运行类似于

while(线程运行){
	取Pc当中的位置,找到对应的指令;
	执行该指令;
	pc++;
}

举个例子:现在有线程A,B;线程A运行到一半的时候被B抢占,这时候,pc寄存器就可以记录下A运行到哪,然后在A再次运行的时候就可以从中断的地方开始运行。

JVM Stacks:

JVM Stacks :线程私有
先看一下官方文档当中的描述:
在这里插入图片描述
在这里插入图片描述

jvm 栈是描述java方法执行的内存模型,它的生命周期和线程相同,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

栈帧

栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。每个方法对应一个栈帧。具体类型结构如图:
在这里插入图片描述

局部变量表

局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。
在这里插入图片描述

局部变量表以变量槽(Variable Slot)为最小单位。特点有以下几个:

 1.虚拟机没有明确指定slot应该占的大小,只是很有导向性地说到每个Slot都应该能存放一个boolean、byte、char、short、int、float、reference或returnAddress类型的数据。一般是32位。
 2.它允许Slot的长度可以随着处理器、操作系统或虚拟机的不同而发生变化,在64位操作系统中采用填充对齐的方法使其一致
 3.long、double这种64位的数据会被分配两个连续Slot空间
 4.连续空间可以通过较小的索引来访问数据。

我们知道在java中有两种方法,一种是类方法,一种是实例方法。
在类方法调用中,所有参数都从局部变量0开始在连续的局部变量中传递。
在实例方法调用中,局部变量0始终指向的是该实例对象,也就是this。也就是说真实的参数是从局部变量1开始存储的。

操作数栈

操作数栈(Operand Stack)也常称为操作栈,是一个后入先出的栈(LIFO LAST IN FIRST OUT).操作数栈的每一个元素可以是任意的Java数据类型,包括long和double。32位数据类型所占的栈容量为1,64位数据类型所占的栈容量为2。在方法执行的任何时候,操作数栈的深度都不会超过max_stacks数据项中设定的最大值。
在这里插入图片描述
让我们通过两段段代码来理解一下:

1.事先我们得准备一个plugin:jclasslib Bytecode Viewer。然后通过show bytecode with jclasslib 打开文件。
在这里插入图片描述 代码 A

	public static void main(String[] args) {
        int i = 8;
        i = i++;    
        System.out.println(i);
    }
    //结果为8

代码 B

	public static void main(String[] args) {
        int i = 8;
        i = ++i;    
        System.out.println(i);
    }
    //结果为9

A 本地方法表
在这里插入图片描述

代码A 点开 方法-code 字节码文件:
在这里插入图片描述
可以直接点击指令进入文档对应位置进行阅读。这边讲解几条

bipush

在这里插入图片描述
(压栈)

istore_< n>

栈顶元素出栈,放入局部变量表号位
在这里插入图片描述

iload_< n>

在这里插入图片描述
将局部变量表 n 号位的值 推入操作数栈

iinc

在这里插入图片描述
根据索引将局部变量表索引位的数增加常量

我们来根据解释一下 代码A:
在这里插入图片描述

1.bipush 8       将8压入操作数栈   , **此时栈内值为8**
2.istore_1 8 出栈 ,放入局部变量表1号位。**此时栈空,局部变量表1号位8**
3.iload_1 将局部变量表1号位的数压栈。 **此时局部变量表1号位 8 ,操作数栈8**
4.iinc 1 by 1 将局部变量表1号位 +1  **此时局部变量表1号位 9 ,操作数栈8**
5.istore_1 8 出栈 ,放入局部变量表1号位。**此时栈空,局部变量表1号位8**
7.iload_1 将局部变量表1号位的数压栈。 **此时局部变量表1号位 8 ,操作数栈8**

代码B:
在这里插入图片描述

1.bipush 8       将8压入操作数栈   , **此时栈内值为8**
2.istore_1 8 出栈 ,放入局部变量表1号位。**此时栈空,局部变量表1号位8**
3.iinc 1 by 1 将局部变量表1号位 +1  **此时局部变量表1号位 9 ,操作数栈空**
4.iload_1 将局部变量表1号位的数压栈。 **此时局部变量表1号位 9 ,操作数栈9**
5.istore_1 9 出栈 ,放入局部变量表1号位。**此时栈空,局部变量表1号位9**
……
动态连接

在这里插入图片描述
从网上偷张图(https://www.cnblogs.com/caca/p/jvm_stack_frame.html)。

简而言之,每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。字节码中的方法调用会用常量池中指向方法的符号引用作为参数,在类加载阶段就转变成直接引用的就是静态解析,在运行期间转换的为动态连接。

JVM提供了五种invoke指令:

invokestatic:调用静态方法。
invokespecial:调用实例构造器<init>方法、私有方法和父类方法。
invokevirtual:(自带多态)调用所有的虚方法。
invokeinterface:调用接口方法,会在运行时再确定一个实现此接口的对象		 
invokedynamic:(lambda表达式函数式调用的时候多用到这条) 先在运行时动态解析出调用点限定符所引用的方法,然后再执行该方法,在此之前的4条调用指令,分派逻辑是固化在Java虚拟机内部的,而invokedynamic指令的分派逻辑是由用户所设定的引导方法决定的。
程序运行正常的返回处理

在这里插入图片描述
简而言之,将其他栈帧的返回值推入调用方操作数栈,适当修改pc使得跳过调用的指令。

附加信息

在这里插入图片描述

Native Method Stacks:本地方法栈:线程私有

在这里插入图片描述
本地方法栈和JVM栈大体相同,区别是JVM Stacks是为java方法服务,Native Method Stacks是为本地方法服务。

Heap:堆:线程共享

在这里插入图片描述

堆当中保存着所有的对象的实例,创建的对象和数组都保存在 Java 堆内存中,也是垃圾收集器进行垃圾收集的最重要的内存区域。关于垃圾回收器和垃圾回收算法,下节再讲。

在这里插入图片描述
可以通过这几个指令设置堆大小

Method Area:方法区:线程共享

在这里插入图片描述

方法区即我们常说的永久代(Perm Space (1.8之前,之后是Meta Space 元空间,注意的是,Perm Space 和Meta Space是方法区不同版本的具体实现,方法区是个抽象的概念)), 用于存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。还有运行时常量池(Runtime Constant Pool)

Runtime Constant Pool:运行时常量池

在这里插入图片描述

用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

Directory Memory 直接内存

直接内存 ,OS管理,Nio访问的就是直接内存(零拷贝)

参考文档

1.官方文档:https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5
2.《深入理解Java虚拟机》

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值