JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器

简介: JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器
+关注继续查看

2020062123300753.png


Pre

JVM-01Java内存区域与内存溢出异常(上)【运行时区域数据】

JVM-02内存区域与内存溢出异常(中)【hotspot虚拟机对象】

JVM-03内存区域与内存溢出异常(下)【OutOfMemoryError案例】


运行时数据区总览


20200621113313484.png


字节码文件被装载子系统装载到JVM中,字节码执行引擎负责执行这些字节码文件。

装载子系统和执行引擎都是C++的实现。

装载子系统: JVM-白话聊一聊JVM类加载和双亲委派机制源码解析

我们重点关注下运行时数据区域 ,先关注线程私有的这3个部分。


线程栈


概要


没给方法被执行的时候,JVM都会同步创建一个栈帧。

这个栈和数据结构的栈结构是一样的, FILO .


举个例子 ,方法A 中调用了方法B , 代码先执行方法A ,此时方法A 入栈, 然后调用方法B,这个时候方法B入栈 。 当方法B执行结束后,方法B出栈,回到方法A执行的地方,方法A继续执行,执行结束 ,方法A出栈。


20200621134337702.png


栈内部主要组成部分

【Java代码】

   public int doSomething() {
        int a = 1 ;
        int b = 2 ;
        int c = (a + b) * 10 ;
        return c;
    }


【javap -c 反汇编】

如何操作的,见文末 ,JVM字节码指令集也见文末

  public int doSomething();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        10
       9: imul
      10: istore_3
      11: iload_3
      12: ireturn
}


0: iconst_1

1: istore_1 【i —> int类型】

iconst_1 是个什么鬼? 查查操作手册



20200621163350493.png


istore_1


20200621163507780.png

iconst_0 和 istore_0 是默认存放调用该方法的对象。

这里就涉及到两个组成部分 【局部变量】 + 【操作数栈】


局部变量

0x04  iconst_1  将 int 型 1 推送至栈顶
0x3c  istore_1  将栈顶 int 型数值存入第二个本地变量
0x05  iconst_2  将 int 型 2 推送至栈顶
0x3d  istore_2  将栈顶 int 型数值存入第三个本地变量
 

比对代码

int a = 1 ;
  int b = 2 ;

iconst_1 , 将 int 1 压入操作数栈 , istore_1 将栈顶 int 型数值存入第二个本地变量 ,这个时候 会先将 1 出栈,然后存入局部变量表。

istore_1 、istore_2 存入本地变量,就是放到了局部变量表。


操作数栈

0x04  iconst_1  将 int 型 1 推送至栈顶
0x05  iconst_2  将 int 型 2 推送至栈顶

这两步的意思 就是将代码中的 a 和 b 对应的值 1 和 2 压入 操作数栈 。

这个操作数栈 本身也是栈结构, FILO . 入栈 出栈


继续

int c = (a + b) * 10 ;
 return c;


 4: iload_1    将第二个 int 型本地变量推送至栈顶  ----> a的值 1 入栈 (操作数栈)
 5: iload_2    将第三个 int 型本地变量推送至栈顶  ----> b的值 2 入栈 (操作数栈)
 6: iadd       将栈顶两 int 型数值相加并将结果压入栈顶  ---->  计算 a+b =3,结果压入栈顶 (a ,b 出栈,计算结果,然后将a+b的结果压入操作数栈)
 7: bipush        10      将单字节的常量值(-128~127)推送至栈顶  -----> 10 入栈 操作数栈)
 9: imul       将栈顶两 int 型数值相乘并将结果压入栈顶  ----> 计算乘积 3 * 10 ,将30压入操作数栈
 10: istore_3  将栈顶 int 型数值存入第四个本地变量  ------>  给 c赋值 
 11: iload_3   将第四个 int 型本地变量推送至栈顶  ----> 压入操作数栈 
 12: ireturn   从当前方法返回 int  ----> 返回


上面的行号 7 到9 ? 没有9 。 我们这个常量10 也要占位置嘛 。

计算 结果肯定是CPU执行的嘛 ,只不过数据是存放在内存中的。

简言之,操作数栈,是程序运行期间需要临时存放数据的内存空间。


动态链接


符号引用 替换为 直接引用。

我们知道在类装载的过程中,有个过程是【解析】



20200621181521290.png


JVM-白话聊一聊JVM类加载和双亲委派机制源码解析

举个例子

 public static void main(String[] args) {
        Artisan artisan = new Artisan();
        artisan.doSomething();
    }

简单说当应用执行到artisan.doSomething()方法( 非静态方法),需要找到这个方法在方法区的常量池中的具体的位置,这个过程就是动态链接


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


方法出口

   public static void main(String[] args) {
        Artisan artisan = new Artisan();
        artisan.doSomething();
    }

    public int doSomething() {
        int a = 1 ;
        int b = 2 ;
        int c = (a + b) * 10 ;
        return c;
    }


doSomething方法执行完要回到main方法中,方法出口中记录的就是记录main方法中的位置,不记录的话 ,不知道回到main方法中的哪一行继续执行哇~


小结



2020062123434479.png


程序计数器


简单理解,可以理解为 记录程序执行的位置。

线程私有。

Java多线程,当线程A没有抢到CPU的执行权,如果没记录程序执行的位置,等下次抢到CPU执行权的时候,这尼玛咋弄? 重新开始执行吗?


显然是不行的,所以需要程序计数器来给每个线程的执行到的行号做下标记。各个现场的程序计数器互不影响,独立存储。


我们来看看javap -c 处理的反汇编


20200621180031125.png


简单理解,可以理解为上面的行号, 实际上存储的是这行代码对应在内存中的指针位置。

字节码 由谁来执行? 肯定是字节码执行引擎嘛 ,所以 字节码执行引擎肯定知道程序的执行位置,这样 字节码执行引擎和程序计数器就关联起来了。


本地方法栈

native 方法 底层C++的


测试demo

package com.gof.test;

 
public class Artisan {


    public static void main(String[] args) {
        Artisan artisan = new Artisan();
        artisan.doSomething();
    }

    public int doSomething() { // public 类型
        int a = 1 ;
        int b = 2 ;
        int c = (a + b) * 10 ;
        return c;
    }
}



javap

用法: javap <options> <classes>
其中, 可能的选项包括:
  -help  --help  -?        输出此用法消息
  -version                 版本信息
  -v  -verbose             输出附加信息
  -l                       输出行号和本地变量表
  -public                  仅显示公共类和成员
  -protected               显示受保护的/公共类和成员
  -package                 显示程序包/受保护的/公共类
                           和成员 (默认)
  -p  -private             显示所有类和成员
  -c                       对代码进行反汇编
  -s                       输出内部类型签名
  -sysinfo                 显示正在处理的类的
                           系统信息 (路径, 大小, 日期, MD5 散列)
  -constants               显示最终常量
  -classpath <path>        指定查找用户类文件的位置
  -cp <path>               指定查找用户类文件的位置
  -bootclasspath <path>    覆盖引导类文件的位置


-c 对代码进行反汇编

 E:\Program Files\Java\jdk1.8.0_161\bin> ./javap -c D:\IdeaProjects\GOF23\target\classes\com\gof\test\Artisan.class > Artisan.txt


查看 Artisan.txt

Compiled from "Artisan.java"
public class com.gof.test.Artisan {
  public com.gof.test.Artisan();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/gof/test/Artisan
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method doSomething:()I
      12: pop
      13: return

  public int doSomething();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        10
       9: imul
      10: istore_3
      11: iload_3
      12: ireturn
}


JVM字节码指令集手册

下载地址戳这里–>提取码:9ru5


相关文章
|
6天前
|
开发框架 前端开发 Java
JVM学习笔记(二)------Java代码编译和执行的整个过程
JVM学习笔记(二)------Java代码编译和执行的整个过程
|
13天前
|
缓存 NoSQL Java
阿里Java三面凉凉:微服务,Redis,JVM一个都搞不懂
前言: 金九银十刚刚过去了,不知道很多小伙伴都拿到自己心仪的offer没有,我这边也收到了一个粉丝投来的消息,说看到阿里的面试真题之后人都是懵的,发现自己一窍不通,下面给大家分享我这个粉丝的经历,以及我在这方面学习的经验。 阿里微服务面试真题 1.单片,SOA 和微服务架构有什么区别? 单片 SOA 和微服务之间的比较 – 微服务访谈问题 单片架构类似于大容器,其中应用程序的所有软件组件组装在一起并紧密封装。 一个面向服务的架构是一种相互通信服务的集合。通信可以涉及简单的数据传递,也可以涉及两个或多个协调某些活动的服务。 微服务架构是一种架构风格,它将应用程序构建为以业务域为模型
25 0
|
15天前
|
Java 开发者
吊打面试官的16000字JVM专属秘籍,又一个Java面试神器!
前言 吊打面试官的16000字JVM专属秘籍,总共包含三部分的内容,从基础到进阶带大家一步步深入理解JVM! 学完就可以在简历上面直接写上精通JVM!
|
25天前
|
架构师 Java 应用服务中间件
每天学四小时:Java+Spring+JVM+分布式高并发,架构师指日可待
每天花四小时学马士兵Java、大数据、Spring、Redis、Jvm、分布式、高并发、坦克大战,你会成为高级架构师 适合小白入门到高级,同时适合工作-两年的同学,因为整套课程全程通过项目演变的过程,从传统单机到整合分布式缓存,高井发负载均衡技术数据一致性方案,再到微服务,注册发现,路由熔断,统一配置管理,服务质量管理,中间件技术选型,底层原理源码分析,覆盖JAVA、spring全家桶、kafka. 多种MQ、缓存数据库技术,docker容器k8s部署,只要跟着学,不只会操作,还能领悟技术发展的因果关系让您面试先人一 步!
|
25天前
|
消息中间件 算法 Java
三面“有赞”Java岗斩获offer:Spring+JVM+并发锁+分布式+算法
年末离职,年初为面试也筹备挺长一段时间,找了不少复习资料,刷了很多题在网上投了很多简历最终面试了有赞,还有幸拿到offer!
|
25天前
|
Java Windows
【问题总结】【JAVA开发】(一)Intellj JVM启动报错
一)启动前提,最新社区版intellj 默认支持1.9 以上。将默认jdk20 替换成jdk8 出现以下问题 Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. Unrecognized option: --add-opens
|
27天前
|
前端开发 Java 程序员
阿里p8 面试官狂推的java面试神器!jvm与多线程面试80问!
说在前面的话 网上各种关于Java太卷的说法很对,Java目前是越来越卷了,但“卷”对个人来说也不一定是坏事,我们得搞清楚Java越来越卷的底层逻辑,才能客观看待这个事。
|
27天前
|
缓存 算法 NoSQL
史上最全499道Java面试题:JVM+分布式+算法+锁+MQ+微服务+数据库
JAVA中的几种基本数据类型是什么,各自占用多少字节。 String类能被继承吗,为什么。 String,Stringbuffer,StringBuilder的区别。 ArrayList和LinkedList有什么区别。 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序。 用过哪些Map类,都有什么区别,HashMap是线程安全的吗,并发下使用的Map是什么,他们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等。
|
27天前
|
NoSQL Java Redis
阿里Java高级岗中间件二面:GC+IO+JVM+多线程+Redis+数据库+源码
虽然“钱多、事少、离家近”的工作可能离技术人比较远,但是找到一份合适的工作,其实并不像想象中那么难。但是,有些技术人确实是认真努力工作,但在面试时表现出的能力水平却不足以通过面试,或拿到高薪,其实不外乎以下 2 个原因:
|
1月前
|
Java
第二季:3.你平时工作用过的JVM常用基本配置参数有哪些?【Java面试题】
第二季:3.你平时工作用过的JVM常用基本配置参数有哪些?【Java面试题】
31 0
相关产品
云迁移中心
推荐文章
更多