[] Gold and three silver four virtual machines JVM stack thorough explanation of the implementation of the principle of

Preface:

Hello, morning, noon, afternoon, good evening. I Java2B brother (micro-channel search Java2B). A missed 985, 996 engineers every day.
You are not very excited about it!
Here Insert Picture Description

2B brother continued to teach everyone JVM knowledge today. The chapters are:
[gold and three silver four -JVM series] CMS collector GC log analysis and positioning problems Comments
[] gold and three silver four JVM virtual machine CMS and G1 collector Detailed

image

What is the JVM

I believe that many small partners are very familiar with, JVM virtual machine is not it? What is a virtual machine that? JVM is not it!
Well this is not nonsense.

JVM can say from us both familiar and unfamiliar, many of my friends at work may be exposed less than this technology, but in an interview often asked (probability quite large), asked about the bad luck, rote learning is useless and in the end, or forget, but it does not matter, today you met 2B brother to me, I give you this for free, said said JVM knowledge, I did not want to let you know I lost count, you can leave a message spray me, If we can, you also do not give me a favor? Do not ink a hurry with it.

ok, on the goods. Here there should be flowers! ❀❀❀❀❀❀❀❀

Acquaintance JVM:

image

I believe everyone is familiar with this picture, which is the whole Java system, including the relationship JDK.JRE.JVM three.

Can be seen in FIG JRE contains JVM, JDK contains JRE.

From the perspective is included: JDK grandfather JRE JVM is the son of the father (if that is not appropriate Liezi) view map

image

We look at the code:

public class App {
   private String name;
   private Object object = new Object();
   /***
    * 运算
    */
   public int add() {
      int a = 1;
      int b = 2;
      int c = (a + b) * 100;
      return c;
   }
   /**
    * 程序入口
    */
   public static void main(String[] args) throws InterruptedException {
      App app = new App();
      int result = app.add();
      System.out.println(result);

   }
}

imageimage

We run the above code output is 300, although this code is very simple, this time has been related to JVM-related knowledge, and when we learn Java-based teacher told us, Java is cross-platform, write once, run everywhere.

That Java is how to achieve cross-platform? Continue to look:

image

通过此图大家就不难发现,我们编译的App.class文件可以在Windows操作系统运行也可以在Linux系统运行,但是两个系统底层的操作指令是不一样的,为了屏蔽底层指令的细节,起到一个跨平台的作用,JVM功不可没,我们常说Java是跨平台还不如说是Jvm跨平台(JRE运行时跨平台)。那Jvm虚拟机是怎么跨平台的?

JVM底层原理:

JVM底层由三个系统构成分别是:类加载、运行时数据区、执行引擎。

image

我们今天重点讲解JVM运行时数据区(栈),其他两块可以关注我之前和后续文章。

我们App.class文件通过类加载子系统从硬盘中读取文件加载到内存中(运行时数据区)。

加载完成之后怎么处理了?(打个比喻 人吃饭 》吃到肚子里》各各器官负责自己工作吸收)

Stack栈:

先讲一下其中的一块内存区域虚拟机栈,大家都知道栈是数据结构,也是线程独有的区域,也就是每一个线程都会有自己独立的栈区域。我们运行App.java输出300就靠线程执行得来的结果。是哪个线程执行的?获取线程快照:“main线程”

栈》数据结构》存储内容》先进后出FILO

image

大家都知道每个方法都有自己的局部变量,比如上图中main方法中的result,add方法中的a b c,那么java虚拟机为了区分不同方法中局部变量作用域范围的内存区域,每个方法在运行的时候都会分配一块独立的栈帧内存区域,我们试着按上图中的程序来简单画一下代码执行的内存活动。

image

执行main方法中的第一行代码是,栈中会分配main()方法的栈帧,并存储math局部变量,,接着执行add()方法,那么栈又会分配add()的栈帧区域。

这里的栈存储数据的方式和数据结构中学习的栈是一样的,先进后出。当add()方法执行完之后,就会出栈被释放,也就符合先进后出的特点,后调用的方法先出栈。

栈帧:

栈帧内部“数据结构”主要由这几个部分组成:局部变量表、操作数栈、方法出口等信息。

image

说了半天,栈帧到底干嘛用的呀?别急讲这个就会涉及到更底层的原理–字节码。我们先看下我们上面代码的字节码文件。

image

APP.class文件看着像乱码,其实每个都是有对应的含义的,oracle官方是有专门的jvm字节码指令手册来查询每组指令对应的含义的。那我们研究的,当然不是这个。

jdk有自带一个javap的命令,可以将上述class文件生成一种更可读的字节码文件。

image

image

Compiled from "App.java"
public com.App {
  public com.App();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: new           #2                  // class java/lang/Object
       8: dup
       9: invokespecial #1                  // Method java/lang/Object."<init>":()V
      12: putfield      #3                  // Field object:Ljava/lang/Object;
      15: return


  public int add();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        100
       9: imul
      10: istore_3
      11: iload_3
      12: ireturn
  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
    Code:
       0: new           #4                  // class com/App
       3: dup
       4: invokespecial #5                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #6                  // Method add:()I
      12: istore_2
      13: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
      16: iload_2
      17: invokevirtual #8              // Method java/io/PrintStream.println:(I)V
      20: return
}


此时的jvm指令码就清晰很多了,大体结构是可以看懂的,类、静态变量、构造方法、add()方法、main()方法。
其中方法中的指令还是有点懵,我们举add()方法来看一下:

   Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        100
       9: imul
      10: istore_3
      11: iload_3
      12: iretu

这几行代码就是对应的我们代码中add()方法中的四行代码。大家都知道越底层的代码,代码实现的行数越多,因为他会包含一些java代码在运行时底层隐藏的一些细节原理。
那么一样的,这个jvm指令官方也是有手册可以查阅的,网上也有很多翻译版本,大家如果想了解可自行百度。

执行流程:

设计代码中的部分指令含义:

第一步:压栈:

将int类型常量1压入操作数栈

0: iconst_1
就是将1压入操作数栈

image

第二步:存储:

将int类型值存入局部变量1

1: istore_1
局部变量1,在我们代码中也就是第一个局部变量a,先给a在局部变量表中分配内存,然后将int类型的值,也就是目前唯一的一个1存入局部变量a

image

第三步:赋值

这两行代码就和前两行类似了。

   2: iconst_2 
   3: istore_2

image

第四步:装载:

从局部变量2中装载int类型值

4: iload_1
5: iload_2
这两个代码是将局部变量1和2,也就是a和b的值装载到操作数栈中

image

第五步:加法

执行int类型的加法

6: iadd
iadd指令一执行,会将操作数栈中的1和2依次从栈底弹出并相加,然后把运算结果3在压入操作数栈底。

image

第六步:压栈:

将一个8位带符号整数压入栈

7: bipush 100
这个指令就是将100压入栈

image

第七步:乘法:

执行int类型的乘法

9: imul
这里就类似上面的加法了,将3和100弹出栈,把结果300压入栈

image

第八步:压栈:

将将int类型值存入局部变量3

10: istore_3
这里大家就不陌生了吧,和第二步第三步是一样的,将300存入局部变量3,也就是c

image

第九步:装载:

从局部变量3中装载int类型值

11: iload_3
从局表变量3加载到操作数栈

image

第十步:返回:

返回int类型值

12: ireturn

我们add方法是被main方法中调用的,所以通过方法出口返回到mian方法中result变量存储方法出口说白了不就是方法执行完了之后要出到哪里,那么我们知道上面add()方法执行完之后应该回到main()方法第三行那么当main()方法调用add()的时候,add()栈帧中的方法出口就存储了当前要回到的位置,那么当add()方法执行完之后,会根据方法出口中存储的相关信息回到main()方法的相应位置。看我图中的红线

image

栈堆关系:

main方法中除了result变量还有一个app变量,app变量指向的是一个对象。那对象是怎么存储的?这儿要在说下局表变量表结构:基本类型和引用类型(Java叫引用C C++叫指针)

image

关系就是:

image

通过引用在栈中的app变量引用堆中的App对象

总结:

讲到这儿相信大家对JVM栈执行原理是不是熟悉了?如果觉得不错欢迎点赞评论。原创不易

如果觉得作者的文章不错,欢迎关注我的微信:Java2B(一位日常996的工程师)。

更正:执行流程过程中灰色背景“操作数栈”应改为“局部变量表”。

image

Here Insert Picture Description
加关注不迷路

Published 241 original articles · won praise 305 · views 540 000 +

Guess you like

Origin blog.csdn.net/HarderXin/article/details/103924865