JAVA虚拟机之-JVM内存模型

Jvm虚拟机 专栏收录该内容
3 篇文章 0 订阅

1.概述部分

小生这里有jvm理论部分知识,车友想了解,请上车。

2.内存模型图

这部分用代码结合图形的模式大致讲了一下,jvm的内存运行模式。
实体类:

package com.wc.jvm;

public class User
{
    private String name;

    private Integer age;

    private String sex;
}

主方法:

package com.wc.jvm;

public class Math
{
    /** 常量 */
    public static final int initData = 888;

    /** 静态变量 */
    public static User user = new User();

    /** 枝干方法 */
    public int compute()
    {
        /** 局部变量 */
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }

    /** 主方法 */
    public static void main(String[] args)
    {
        Math math = new Math();
        math.compute();
        // 方法出口
        System.out.println("test");
    }
}

图形:
在这里插入图片描述
结合代码,以及jvm理论部分我们可以知道,一个main线程交互部分主要包括外部内存,以及虚拟机栈、程序计数器、共享内存堆。

虚拟机栈我们就要了解一下栈帧,栈帧是jvm开辟出来的一块内存区域,存放每个方法的局部变量、操作数栈、动态链接、方法出口等等。

局部变量表:顾名思义,想必不用解释大家应该明白它的作用了吧。就是用来存储方法中的局部变量(包括在方法中声明的非静态变量以及函数形参)。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。局部变量表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。

操作数栈:想必学过数据结构中的栈的朋友想必对表达式求值问题不会陌生,栈最典型的一个应用就是用来对表达式求值。想想一个线程执行方法的过程中,实际上就是不断执行语句的过程,而归根到底就是进行计算的过程。因此可以这么说,程序中的所有计算过程都是在借助于操作数栈来完成的。

动态链接:指向运行时常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。

方法出口:方法返回地址,当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。

由于每个线程正在执行的方法可能不同,因此每个线程都会有一个自己的Java栈,互不干扰。

3.汇编出真知

汇编语言是最接近底层的,我们通过汇编语言可以很清楚的了解一个java类的加载以及方法的运行过程。

可以用jdk自带的javap命令进行反汇编。
在这里插入图片描述
打开idea terminal运行 javap有对javap的用法介绍。

D:\company project\hrht project\java-groovy\target\classes\com\wc\jvm>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>    覆盖引导类文件的位置

运行javap -c Math.class,得到整个main方法的底层执行过程。

D:\company project\hrht project\java-groovy\target\classes\com\wc\jvm>javap -c Math.class
Compiled from "Math.java"
public class com.wc.jvm.Math {
  public static final int initData;

  public static com.wc.jvm.User user;

  public com.wc.jvm.Math();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public int compute();
    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

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/wc/jvm/Math
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method compute:()I
      12: pop
      13: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      16: ldc           #6                  // String test
      18: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      21: return

  static {};
    Code:
       0: new           #8                  // class com/wc/jvm/User
       3: dup
       4: invokespecial #9                  // Method com/wc/jvm/User."<init>":()V
       7: putstatic     #10                 // Field user:Lcom/wc/jvm/User;
      10: return
}

汇编出来的语言,包括静态常量、静态变量、构造方法、主方法、枝干方法等等,就是我们之前java代码以另一种语言形态的展示。

我们可以根据《jvm指令手册》可以很清楚的明白这段代码的整个运行的流程。
在这里插入图片描述

 public com.wc.jvm.Math();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

0x2a aload_0 将第一个引用类型本地变量推送至栈顶
0xb7 invokespecial 调用超类构建方法, 实例初始化方法, 私有方法
0xb1 return 从当前方法返回 void

public int compute();
    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

0x04 iconst_1 将 int 型 1 推送至栈顶
0x3c istore_1 将栈顶 int 型数值存入第二个本地变量
0x05 iconst_2 将 int 型 2 推送至栈顶
0x3d istore_2 将栈顶 int 型数值存入第三个本地变量
0x1b iload_1 将第二个 int 型本地变量推送至栈顶
0x1c iload_2 将第三个 int 型本地变量推送至栈顶
0x60 iadd 将栈顶两 int 型数值相加并将结果压入栈顶
0x10 bipush 将单字节的常量值(-128~127)推送至栈顶
0x68 imul 将栈顶两 int 型数值相乘并将结果压入栈顶
0x3e istore_3 将栈顶 int 型数值存入第四个本地变量
0x1d iload_3 将第四个 int 型本地变量推送至栈顶
0xac ireturn 从当前方法返回 int

在这里插入图片描述
程序中的所有计算过程都是在借助于操作数栈来完成的。

我想这里大家对java代码运行的流程有了一个基础的直观的了解。博主也是从以前的看完什么什么大牛的视频讲解,什么什么大牛的博客啥的,看完觉得是那样的,但是为什么是那样的一脸懵逼,不能很深入的了解,然后过段时间忘记的彻彻底底,记不起来到底jvm是个什么鬼,最悲催的事情莫过于此,花费了时间以及精力去学习了解,后面还是一脸懵逼,浪费了时间。博主这种图形结合的方式,我想大家认真看了,应该最起码能说个一二,博主也是看网上付费视频以后的总结,又不到位的地方麻烦大家批评指正,共通学习共通进步。

4.注意点

枝干方法中的局部变量和main方法中的动态变量还是有所区分的,像局部变量a b 基本用完就销毁的,main方法中的 对象math以及 静态变量user 他们主要存放在共享内存堆中,栈中存储的实际是指向堆的引用。

因为方法区中的静态变量user实际内存是指向堆的,所以图形方法区指向堆也是没问题的。

博主后期也会自己消化吸收不断完善jvm这块知识,如有不到位之处,欢迎批评指正。

  • 0
    点赞
  • 1
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值