JVM的简介及内部结构
JVM介绍
1.jvm(java virtual machine)
- java程序的跨平台
我们编写一个helloWorld.java,通过javac命令生成helloWorld.class字节码文件,再通过java命令由jvm生成机器码。
跨平台特性: 我们只需编写一份代码,可以在不同操作系统中执行。但是不同的操作系统它底层硬件与指令存在区别,那java如何做到一份代码在不同操作系统中运行的呢?
原因: 在oracle官网提供不同操作系统的JDK,不同JDK里面也就包含不同的JVM。在通过java命令根据不同操作系统的JVM生成不同的机器码,这样就完成了跨平台的效果。 - JVM内部大概运行流程
上图中JVM虚拟机分为大致的三部分:类装载子系统、内存模型(虚拟机内存区域)、字节码执行引擎
A.Math.java通过javac命令生成Math.class字节码文件
B.Math.class通过java命令,JVM中的类装载子系统会将字节码文件加载到JVM内存区域,最终由字节码执行引擎运行虚拟机内存区域中的方法区里的代码,生成机器码。
2.实例分析
public class hello_test {
public int math(){
int a =11;
int b = 20;
int c = a + b;
return c;
}
public static void main(String[] args) {
hello_test helloTest = new hello_test();
int a = helloTest.math();
System.out.println(a);
}
}
一:当程序运行时,会根据线程为其分配 栈(线程) 内存空间,用来存放线程中用到的局部变量。
二:栈中又包含一个个栈帧,栈帧用来存放线程中方法用到的方法局部变量。上面代码有两个方法,一个main方法和一个math方法。栈帧采用栈的数据结构进行存储(先进后出),上面程序先运行main方法,就先将main()-栈帧存入栈中,当运行到int a = helloTest.math();,又将math()-栈帧存入栈中,而当math()方法运行完,整个math()-栈帧移出栈。
三:栈帧中包含:局部变量表、操作数栈、动态链接、方法出口
四:局部变量表、操作数栈后面通过代码进行说明。类中的方法放在方法区(元空间),而栈帧中的动态链接则是记录是方法存放的地址,程序会根据地址去方法区找到位置进行执行。
五:方法出口:字节码执行引擎执行完helloTest.math();后,需要回到主方法继续执行下面代码。那程序怎么知道该回到那里执行,所以方法出口也就是记载此方法执行完后,该去哪里执行。当然有返回值的时候,返回值是保存在方法出口里。
六:通过字节码文件查看局部变量表、操作数栈的作用
想通过代码分析JVM内部机制,则需对java文件转成字节码文件(.class),但是字节码文件是让JVM运行,可读性不强,这里需要将.class文件反汇编,方便我们查阅。具体操作如下:
A.在java文件位置处打开Windows终端,执行javac命令生成.class文件
B.执行javap -c xxx.class > xxx.txt ,对代码进行反汇编的内容保存在txt文本中
方法一:如果使用eclipse工具编程,选中类名,点击右键,选择show in —>terminal。在下方弹出来的控制台执行A、B两步。生成txt文件。
方法二:如果使用idea工具编程,选中类名,点击右键,选择open in terminal。在下方弹出来的控制台执行A、B两步。生成txt文件。
方法三:在电脑本地找到你写的java文件,cmd打开Windows终端,执行A、B两步。生成txt文件。
生成的txt文件如下:
通过对math()方法的分析,加深局部变量表、操作数栈的认识。根据上面的内容去oracle官网网站查询JVM指令手册,理解具体执行含义。
0: bipush 11
查询JVM指令手册:0x10 bipush 将单字节的常量值(-128~127)推送至操作数栈
就是先将11这个值放进操作数栈
2: istore_1
查询JVM指令手册:0x3c istore_1 将操作数栈int型数值存入第二个本地变量
这里需要解释一下,第一个本地变量默认为this。看上面代码不难看出,第二个变量就是a,这条代码也就是将操作数栈中保存的11赋值给变量a
3: bipush 20
查询JVM指令手册:0x10 bipush 将单字节的常量值(-128~127)推送至操作数栈
就是将20这个值放进操作数栈
5: istore_2
查询JVM指令手册:0x3d istore_2 将操作数栈int型数值存入第三个本地变量
就是将操作数栈中保存的20赋值给变量a
6: iload_1
查询JVM指令手册:0x1b iload_1 将第二个int型本地变量推送至操作数栈
就是将变量a的值放在操作数栈
7: iload_2
就是将变量b的值放在操作数栈
8: iadd
查询JVM指令手册:0x60 iadd 将操作数栈两int型数值相加并将结果压入操作数栈
…
通过上面可以看出局部变量表存放变量的、操作数栈临时存放数据以及做运算时使用。
七:我们都知道java是多线程运行,当优先级更高的线程抢走CPU的时间片后,当前线程就会被挂起。当挂起线程被唤起运行时,又是如何知道挂起前运行到哪里?这时候就需要程序计数器。当字节码执行引擎运行完一段程序,就会在程序计数器记录一下位置,这样即使被挂起,也知道程序是在哪里停止的。
本文地址:https://blog.csdn.net/study_study_know/article/details/110205839
下一篇: MacBook Pro怎么设置热点?