#JVM 中的位置
JVM是运行在操作系统之上的,他与硬件没有直接的交互。
不同的操作系统装的JVM是有区别的。
JVM的整体结构
JVM是解释运行字节码(.class)文件的。
类加载器子系统:字节码文件需要使用类加载器子系统加载到内存当中,生成一个大的class对象。(过程涉及到加载、链接、初始化)
类加载子系统,加载字节码之后会在方法区生成class实例
方法区、堆:多线程共享堆和方法区
栈(虚拟机栈)、本地方法栈、程序计数器:每个线程独有一份的。
执行引擎:解释器、即时编译器(JIT)、GC。对于反复执行的代码希望能够提前编译出来。就会使用JIT。
执行引擎主要作用:操作系统只能识别机器指令,字节码指令是不同于机器指令的,要想字节码能够解释执行就需要借助执行引擎。执行引擎就充当的把高级语言翻译成机器语言。
Java代码的执行流程
java源文件通过编译生成字节码文件、字节码文件进行解释执行。
JIT编译器,保证了程序的性能,它会把一些热点代码缓存到本地。
JVM的架构模型
JVM 是基于栈的指令集架构
创建一个简单的类
package com.atguigu.java;
public class StackruTest {
public static void main(String[] args) {
int a=1+2;
}
}
使用javap -v StackruTest.class 反编译字节码文件
Classfile /D:/WljFile/YCSun/JVMDemo/chapter01/target/classes/com/atguigu/java/StackruTest.class
Last modified 2022-5-25; size 434 bytes
MD5 checksum 8a8df5dd8122e079ff5fc438f8a1fcef
Compiled from "StackruTest.java"
public class com.atguigu.java.StackruTest
minor version: 0
major version: 49
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#19 // java/lang/Object."<init>":()V
#2 = Class #20 // com/atguigu/java/StackruTest
#3 = Class #21 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 Lcom/atguigu/java/StackruTest;
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 args
#14 = Utf8 [Ljava/lang/String;
#15 = Utf8 a
#16 = Utf8 I
#17 = Utf8 SourceFile
#18 = Utf8 StackruTest.java
#19 = NameAndType #4:#5 // "<init>":()V
#20 = Utf8 com/atguigu/java/StackruTest
#21 = Utf8 java/lang/Object
{
public com.atguigu.java.StackruTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/atguigu/java/StackruTest;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=2, args_size=1
0: iconst_3
1: istore_1
2: return
LineNumberTable:
line 5: 0
line 6: 2
LocalVariableTable:
Start Length Slot Name Signature
0 3 0 args [Ljava/lang/String;
2 1 1 a I
}
```xml
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=2, args_size=1
0: iconst_3 //初始化一个3
1: istore_1 保存起来 1是 操作数栈中的索引位置
2: return
LineNumberTable:
line 5: 0
line 6: 2
LocalVariableTable:
Start Length Slot Name Signature
0 3 0 args [Ljava/lang/String;
2 1 1 a I
Code: 是方法的指令内容
重新把main方法写的复杂一些
public class StackruTest {
public static void main(String[] args) {
int a= 2;
int b= 3;
int c=a+b;
}
}
重新反编译字节码
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: iconst_2 初始化 2
1: istore_1 保存
2: iconst_3 初始化3
3: istore_2 保存
4: iload_1 加载1(猜测istore_1)
5: iload_2 加载2 (猜测istore_2)
6: iadd 进行相加计算
7: istore_3 (计算的结果保存3)
8: return
LineNumberTable:
line 5: 0
line 6: 2
line 7: 4
line 8: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
2 7 1 a I
4 5 2 b I
8 1 3 c I
}
其他例子
Code:
JVM的生命周期
JVM的启动
java虚拟机的启动是通过引导类加载器(bootstrap class loader )创建一个初始类(initial class)来完成的,这个类是有虚拟机的具体实现指定的。
加载去分为: 引导类加载器、扩展类加载器、系统类加载器
在代码中自己定义的类需要加载是通过系统类加载器(或者应用类加载器)来实现的,定义的类没有默认是继承Object 的,Object 作为核心API是需要引导类进行加载的。
父类的加载是早于子类的
JVM的执行
- 一个运行的java虚拟机有着一个清晰的任务:执行java程序
- 程序开始执行时它才会运行,程序结束时它就会停止
- 执行一个所谓的java程序的时候,真真正正在执行的是一个叫做java虚拟机的进程
查看JVM进程
public class StackruTest {
public static void main(String[] args) {
int a= 2;
int b= 3;
int c=a+b;
try {
//睡一会
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
使用jps 查看 查看程序执行的进程
D:\WljFile\YCSun\JVMDemo\chapter01\target\classes\com\atguigu\java>jps
18516 OracleIdeLauncher
28792 Launcher
29256 StackruTest 程序执行的进程 PID 29256
2284 Jps
29404 RemoteMavenServer36
3932
线程结束 没有运行的线程 再次使用jps 查看进程
D:\WljFile\YCSun\JVMDemo\chapter01\target\classes\com\atguigu\java>jps
18516 OracleIdeLauncher
23156 Jps
22056 Launcher
29404 RemoteMavenServer36
3932