JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

2、运行时数据区

哔哩哔哩 尚硅谷视频 宋红康老师

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

2.1、程序计数器(PC寄存器)

作用

PC寄存器用来存储指向下一条指令的地址,也就是即将要执行指令的代码。由执行引擎读取下一条指令

注意:每个线程独一份PC寄存器

测试

package com.mhy.day02;

public class PCTest01 {
    public static void main(String[] args) {
        int i = 10;
        int j = 20;
        int k = i + j;

        System.out.println(k);
    }
}

使用 javap -v PCTest01.class 进行反编译后

 Code:
      stack=2, locals=4, args_size=1
         0: bipush        10
         2: istore_1
         3: bipush        20
         5: istore_2
         6: iload_1
         7: iload_2
         8: iadd
         9: istore_3
        10: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        13: iload_3
        14: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        17: return

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

2.2、虚拟机栈

基本内容

  • Java虚拟机栈,早期也叫Java栈,每个线程在创建时都会创建一个虚拟机栈,其内存保存一个一个的栈帧,对应一次一次Java方法的调用 注意:每个栈是线程私有的
  • 生命周期和线程一致
  • 作用:主管Java程序的运行,它保存方法的局部变量、部分结果,并参与方法的调用与返回

栈帧的内部结构

  • 局部变量表(Local Variables)
  • 操作数栈(Operand Stack)(或表达式栈)
  • 动态链接(Dynamic Linking)(或指向运行时常量池的方法引用)
  • 方法返回地址(Return Address)(或方法正常退出或者异常退出的定义)
  • 一些附加信息

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

1.局部变量表(Local Variables)

  • 局部变量表也被称之为局部变量数组或本地变量表
  • 定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,这些数据类型包括各类基本数据类型、对象引用(reference),以及returnAddress类型
  • 由于局部变量表也是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题
  • 局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的Code属性的maxmum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的
  • 方法嵌套调用的次数由栈的大小决定
  • 局部变量表中的变量只在当前方法调用中有效

测试:

package com.mhy.test1;

import java.util.Date;

public class LocalVariablesTest {
    private int count = 0;

    public static void main(String[] args) {
        LocalVariablesTest localVariablesTest = new LocalVariablesTest();
        int num = 1;
        localVariablesTest.fun1();
        System.out.println(localVariablesTest.count);
    }

    public void fun1() {
        Date date = new Date();
        String str = "Hello JVM";
        double dd = 0.22;
        String s = fun2(str, date);
        System.out.println(s);
    }

    public String fun2(String string,Date date){
        System.out.println(date);
        System.out.println(string);
        System.out.println(fun3());
        return "fun2";
    }

    public int fun3(){
        int a = 1;
        {
            int b = 2;
            b = a + b;
        }
        int c = a + 1;
        return c;
    }
}

根据编译的class用 jclasslib is a bytecode viewer 来查看结果

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

先查看main 是static类型的

public static void main(String[] args) {
    LocalVariablesTest localVariablesTest = new LocalVariablesTest();
    int num = 1;
    localVariablesTest.fun1();
    System.out.println(localVariablesTest.count);
}

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

注意:这里局部变量最大槽数是指局部变量占的大小,一般的int、char、引用类型等等占1个槽,long、double等等占2个槽

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

查看非static类型的方法

public String fun2(String string,Date date){
    System.out.println(date);
    System.out.println(string);
    System.out.println(fun3());
    return "fun2";
}

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

带有作用域的局部变量

public int fun3(){
    int a = 1;
    {
        int b = 2;
        b = a + b;
    }
    int c = a + 1;
    return c;
}

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

变量的分类

  1. 按照数据类型分类:
  2. 基本数据类型
  3. 引用数据类型
  4. 按照类中声明的位置分类:
  5. 成员变量:在使用之前都经历过默认初始化阶段
    • 类变量:linking 的 prepare 阶段赋默认值 —–> initial 阶段初始化
    • 实例变量:随着对象的创建会在堆空间中分配实例变量空间,并进行默认赋值
  6. 局部变量:在使用前必须赋值,否则编译不通过

2.操作数栈(Operand Stack)

操作数栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push)和出栈(pop)

测试

package com.mhy.test1;

public class OperandStackTest {
    public static void main(String[] args) {
        new OperandStackTest().test();
    }
    public void test(){
        byte a = 11;
        int b = 12;
        int c = a + b;
    }
}

指令

 0 bipush 11
 2 istore_1
 3 bipush 12
 5 istore_2
 6 iload_1
 7 iload_2
 8 iadd
 9 istore_3
10 return

代码跟踪

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

这里可以看出局部变量的长度为4还一个0位置为this,操作数栈的深度为2

3.动态链接(Dynamic Linking)

每一个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用,包含这个引用的目的就是为了支持当前方法代码能够实现动态链接
动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

4.方法的调用

虚方法与非虚方法

  • 非虚方法
  • 该方法在编译器就确定了具体的调用版本,这个版本在运行时是不可变的,这样的方法称为非虚方法
  • 静态方法、私有方法、final修饰的方法、实例构造器、父类方法都是非虚方法
  • 除了上面以外的方法都是虚方法

虚方法与非虚方法的指令

  • 普通指令
invokestatic : 调用静态方法,解析阶段确定唯一方法版本
invokepecial : 调用方法、私有及父类方法,解析阶段确定唯一方法版本
invokevirtual : 调用所有虚方法
invokeinterface : 调用所有接口方法
  • 动态指令
invokedynamic : 动态解析需要调用的方法,然后执行

方法重写的本质

  1. 找到操作数栈顶的第一个元素所执行的对象的实际类型,记为 C
  2. 如果在过程结束后:如果不通类型 C 中找到与常量中的描述符合简单名称都相符的方法,则进行访问权限校验,如果通过就返回这个方法的直接引用,查找过,则返回 java.lang.IllegalAccessError 异常
  3. 否则,按照继承关系依次从下倒上对 C 的各个父类进行第二步的搜索与校验
  4. 如果始终没有找到合适的方法,则抛出 java.lang.AbstractMethodError 异常

java.lang.IllegalAccessError 异常

程序试图访问或修改一个属性或者方法,这个属性或者方法你没有权限,就会引起编译时异常,一般在运行时发生

5.方法返回地址(Return Address)

  • 存放调用该方法的PC寄存器的值
  • 一个方法的结束有两种方式
  • 正常执行完成
  • 出现未处理的异常,非正常退出
  • 正常退出:调用者的PC计数器的值作为返回地址,即调用该方法的指令的下一条指令的地址;异常退出,有异常表来决定返回地址

2.3、本地方法接口

JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

什么是本地方法?

一个 Native Method 就是一个Java调用非java代码的接口。一个 Native Method 就是这样一个方法,该方法非java语言实现,比如说C。

为什么要使用Native Method?

  • 与Java环境外交互:有时Java应用需要与Java外面的环境交互,这是本地方法存在的主要原因
  • 与操作系统交互:通过使用本地方法,我们得以用Java实现了jre的与底层系统的交互,甚至JVM的一部分代码都是使用C写的
  • Sun Java:Sun的解释器就是用C写的,它使得它能像一些普通的C一样与外部交互

2.4、本地方法栈

Java虚拟机用以管理Java方法的调用,而本地方法栈用于管理本地方法的调用-

  • 当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。它和虚拟机拥有同样的权限
  • 本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区
  • 它甚至可以直接使用本地处理器中的寄存器
  • 直接从本地内存的堆中分配任意数量的内存
  • 本不是所有的JVM都支持本地方法,因为Java虚拟机规范并没有明确要求本地方法栈的使用语言、具体实现方法、数据结构等。
  • 在 Hotspot JVM 中,直接将本地方法栈和虚拟机栈合二为一

Original: https://www.cnblogs.com/shuisanya/p/16693651.html
Author: 水三丫
Title: JVM学习 运行时数据区 PC寄存器、本地方法栈、虚拟机栈

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/581430/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Jmeter性能测试场景的创建和运行

    目录 性能测试场景的分析 项目背景 Jmeter指标 性能测试场景的设计以及准备 * 性能测试的总结 性能测试场景的分析 项目背景 ​ 实际工作中,我们拿到一个项目一般来说都会是项…

    Linux 2023年6月14日
    094
  • centos系统和Ubuntu系统命令区别以及常见操作

    一.前言 二.系统环境 三.命令区别 3.1 使用习惯和命令区别 3.2 服务管理的区别 3.3 软件包信息区别 四.Ubuntu系统常见操作 4.1 Ubuntu系统apt和ap…

    Linux 2023年6月7日
    0230
  • 面试连环炮系列(二十六):什么情况下JVM频繁发生full GC

    什么情况下JVM频繁发生full GC; 在实际项目什么代码导致full GC;线上怎么排查是哪个程序导致的ful GC 1. 什么情况下JVM频繁发生full GC?full g…

    Linux 2023年6月6日
    0125
  • 分布式系统中数据存储方案实践

    数据膨胀的时候,必然放大细节。 一、背景简介 在项目研发的过程中,对于数据存储能力的依赖无处不在,项目初期,相比系统层面的组件选型与框架设计,由于数据体量不大,在存储管理方面通常容…

    Linux 2023年6月14日
    088
  • 大数据之Hadoop的HDFS存储优化—异构存储(冷热数据分离)

    异构存储主要解决,不同的数据,储存在不同类型的硬盘中,达到最佳性能的问题 1)存储类型 RAM_DISK:内存镜像文件系统 SSD:SSD固态硬盘 DISK:普通磁盘,在HDFS中…

    Linux 2023年6月8日
    092
  • 好记性不如烂笔头系列之STM32 SysTick 精确延时(非中断方式)

    在stm32里,如果想精确延时又不需要中断做别的事; 就可以选择这个stick延时方法,简单易用。其寄存器容易设置,如下图 寄存器一目了然, 就是有一点 其记数只有24位,所以最大…

    Linux 2023年6月13日
    0123
  • 【设计模式】Java设计模式-组合模式

    Java设计模式 – 组合模式 😄 不断学习才是王道🔥 继续踏上学习之路,学之分享笔记👊 总有一天我也能像各位大佬一样🏆原创作品,更多关注我CSDN: 一个有梦有戏的人…

    Linux 2023年6月6日
    0123
  • Springboot 的一些默认配置规则

    本文样例说明仅适用 maven 环境和语法,但所述内容也适用 gradle 1. logback 日志默认为 slf4j + logback 框架,引入如下 jar 之后,就自动引…

    Linux 2023年6月6日
    088
  • [20220302]oracle如何定位使用library cache mutex 2.txt

    [20220302]oracle如何定位使用library cache mutex 2.txt –//这个问题实际上困扰我很久,我开始以为library cache b…

    Linux 2023年6月13日
    083
  • Django_模型详解

    Django_模型ORM Django中内嵌了ORM框架,不需要直接编写SQL语句进行数据库操作,而是通过定义模型类,操作模型类来完成对数据库中表的增删改查和创建等操作。 O是ob…

    Linux 2023年6月7日
    0110
  • Redis的slot迁移工具

    工具下载: https://github.com/eyjian/redis-tools/blob/master/move_redis_slot.sh 支持迁移已有的keys。 #!…

    Linux 2023年5月28日
    0104
  • 用 shell 脚本做命令行工具扩展

    问题的提出 公司开发机与远程服务器之间有严格的隔离策略,不能直接使用 ssh 登录,而必需通过跳板机。这样一来,本地与服务器之间的一些文件传输变得非常不便。经过咨询,运维教了我一招…

    Linux 2023年5月27日
    0124
  • 用go把博客园博客下载到本地Hexo目录下

    找到cookie 直接浏览器F12 巴拉巴拉 直接上代码 用hexo建静态博客的话,go文件在 \source\_posts目录下,run之后将会在此目录下生成cnblogs文件夹…

    Linux 2023年6月7日
    095
  • Python之pexpect详解

    Pexpect程序主要用于人机对话的模拟,就是那种系统提问,人来回答yes/no,或者账号登陆输入用户名和密码等等的情况。因为这种情况特别多而且繁琐,所以很多语言都有各种自己的实现…

    Linux 2023年6月14日
    095
  • 配置git环境与项目创建

    主要用于记录上课笔记,方便以后复习 acgit的地址:https://git.acwing.com/wyw/kob1/ 1. 项目模块的包含 1.1 采用前后端分离 Web端大概框…

    Linux 2023年6月6日
    0118
  • 01-MySQL连接查询、聚合函数

    1、连接查询 1.1、左连接 以左表为基准进行查询,左表数据回全部显示出来 右表中如果匹配连接条件的数据则显示相应字段的数据,如果不匹配,则显示为NULL 1.2、右连接 以右表为…

    Linux 2023年6月7日
    0128
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球