jvm初识

一、什么是jvm?
1.1对比物理机

物理机:
在这里插入图片描述
jvm:
在这里插入图片描述
Java虚拟机与物理机

  • Class文件类比输入设备
  • CPU指令集类比输出设备
  • JVM类比存储器、控制器、运算器等
1.2 JVM products

有哪些版本?

  • Oracle:HotSpot、JRockit
  • IBM:J9 VM
  • Ali:TaobaoVM
  • Zual:Zing

最常用的目前是HotSpot,可以通过java -version命令查看

1.3 JDK JRE JVM 三者之间的关系

官网: https://docs.oracle.com/javase/8/docs/index.html
在这里插入图片描述
jre 包含了jvm,jdk 包含jdk

1.4 结合JDK看JVM
  1. 能够把Class文件翻译成不同平台的CPU指令集
  2. 也是Write Once Run Anywhere的保证
    在这里插入图片描述
1.5 HotSpot JVM Architecture

https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html
在这里插入图片描述

二、 class file

Java源码文件、Kotlin源码文件、Groovy源码文件等都可以编译成class文件执行。

2.1 java 测试类
public class User {
    private Integer age;
    private String name = "Jack";
    private Double salary = 100.0;
    private static String address;

    public void say() {
        System.out.println("Jack Say...");
    }

    public static Integer calc(Integer op1, Integer op2) {
        op1 = 3;
        Integer result = op1 + op2;
        return result;
    }
}
2.2 编译过程

javac User.java->User.class
在这里插入图片描述

2.3Class 文件格式

官方文档
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html
class 文件是一个16进制的文件
在这里插入图片描述

IDEA插件(BindED)——查看class文件的十六进制

文件的格式

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
2.4 文件的解析

user.class对应的16进制文件
在这里插入图片描述
对比类文件的格式,和上面16进制数据进行解析

  1. cafebabe
    u4 magic 对应的就是16进制中的 cafebabe ,cafebabe 代表的是一个class类文件的表示,只要是一个class文件就一定是 cafebabe 开头

  2. 0000+0034:minor_version+major_version
    16进制的34等于10进制的52,表示JDK的版本为8

  3. 0043:constant_pool_count
    16进制的43等于10进制的67,表示常量池中常量的数量是66

  4. cp_info:constant_pool[constant_pool_count-1]
    字面量:文本字符串,final修饰的常量等
    符号引用:类和接口的全限定名、字段名称和描述符、方法名称和描述符

  5. The constant pool
    官网: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4

常量的基本结构

cp_info {
	2u1 tag;
	u1 info[];
}

在这里插入图片描述

2.5 反汇编

javap ‐v ‐c ‐p User.class > User.txt 进行反编译,查看字节码信息和指令等信息
JVM相对class文件来说可以理解为是操作系统;class文件相对JVM来说可以理解为是汇编语言或者机 器语言。

3.类加载机制

官网:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html

3.1 加载
3.3.1 4种ClassLoader

在这里插入图片描述

3.1.2 双亲委派机制
				try {
                    if (parent != null) {
                    	// 先找父加载器
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

  1. 检查某个类是否已经加载
    自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个Classloader已加载,就视为已加载此类,保证此类只所有ClassLoader加载一次。
  2. 加载的顺序
    自顶向下,也就是由上层来逐层尝试加载此类。
3.1.3 java代码
public class Demo {
    public static void main(String[] args) {
        // App ClassLoader
        System.out.println(new Demo().getClass().getClassLoader());
        // Ext ClassLoader
        System.out.println(new Demo().getClass().getClassLoader().getParent());
        // Bootstrap ClassLoader
        System.out.println(new Demo().getClass().getClassLoader().getParent().getParent());

    }
}

结果
在这里插入图片描述
bootstrap classloader 是c语言实现的打印不出来

3.1.4 破坏双亲委派
  1. tomcat
    在这里插入图片描述

(2)SPI机制
(3)OSGi

3.2Linking
3.2.1 Verification

保证被加载类的正确性

3.2.2 Preparation

为类的静态变量分配内存,并将其初始化为默认值

3.2.3 Resolution

把类中的符号引用转换为直接引用

3.3 Initialization

对类的静态变量,静态代码块执行初始化操作

04 运行时数据区

官网:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

4.1Method Area(方法区)

JVM运行时数据区是一种规范,真正的实现在JDK 8中就是Metaspace,在JDK6或7中就是Perm Space方法区是各个线程共享的内存区域,在虚拟机启动时创建,虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却又一个别名叫做Non-Heap(非堆),目的是与Java堆区分开来。用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。当方法区无法 满足内存分配需求时,将抛出OutOfMemoryError异常。

4.1.1常量池和运行时常量池

The Constant Pool:https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-
4.4
The Run-time Constant Pool:https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-
2.html#jvms-2.5.5

4.1.2 String常量到底存在哪
public class SCPDemo {
	public static void main(String[] args) {
	String str1	= "jack"; // 这个常量一定会放到字符串常量池中
	String str2	= "jack";
	String str3=new String("Jack");
	String str4=str3.intern(); // 找字符串常量池中是否有该常量,如果有就直接返回,如果没有再创建
	
	// equals 只会比较值 == 会比较地址
	System.out.println(str1.equals(str2)); // true 
	System.out.println(str1==str2); // true
	
	System.out.println(str1.equals(str3)); // true
	 System.out.println(str1==str3); // false

在这里插入图片描述

4.2 Heap(堆)
  1. Java堆是Java虚拟机所管理内存中最大的一块,在虚拟机启动时创建,被所有线程共享
  2. Java对象实例以及数组都在堆上分配
  3. 堆内存空间不足时,也会抛出OOM
4.2.1 Java对象内存布局

一个Java对象在内存中包括3个部分:对象头、实例数据和对齐填充
在这里插入图片描述

4.2.2 方法区引用指向堆

在这里插入图片描述

4.2.3 堆指向方法区

在这里插入图片描述

4.3 Java Virtual Machine Stacks(Java虚拟机栈)

(1)虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。换句话说,一个Java线程的运行状态, 由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的,独有的,随着线程的创建而创建。
(2)每一个被线程执行的方法,为该栈中的栈帧,即每个方法对应一个栈帧。调用一个方法,就会向栈中压入一个 栈帧;一个方法调用完成,就会把该栈帧从栈中弹出。

4.3.1 代码
1 void a(){
2 b();
3 }
4 void b(){
5 c();
6 }
4.3.2 压栈出栈

在这里插入图片描述

4.3.3 Frame(栈帧)

在这里插入图片描述
在这里插入图片描述

1  public static java.lang.Integer calc(java.lang.Integer, java.lang.Integer);
2  descriptor: (Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;
3  flags: ACC_PUBLIC, ACC_STATIC
4  Code:
5  stack=2, locals=3, args_size=2
6  0: iconst_3 // 将int类型常量3压入[操作数栈]
7  1: invokestatic #11 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
8  4: astore_0 // 将int类型值存入[局部变量0]
9  5: aload_0 // 从[局部变量0]中装载int类型值入栈
10 6: invokevirtual #12 // Method java/lang/Integer.intValue:()I
11 9: aload_1 // 从[局部变量1]中装载int类型值入栈
12 10: invokevirtual #12 // Method java/lang/Integer.intValue:()I
13 13: iadd // 将栈顶元素弹出栈,执行int类型的加法,结果入栈
14 14: invokestatic #11 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
15 17: astore_2 // 将栈顶int类型值保存到[局部变量2]中
16 18: aload_2 // 从[局部变量2]中装载int类型值入栈
17 19: areturn // 从方法中返回int类型的数据
18 LineNumberTable:
19 line 11: 0
20 line 12: 5
21 line 13: 18

4.3.5 index为0还是1

对于Java虚拟机栈中的Local Variables,到底是从0开始还是1开始,要看当前方法是static还是实例方法。
如果是static 方法,局部变量表从0开始,实例方法,是从1开始,0留给this关键字

4.3.6栈引用指向堆

在这里插入图片描述

4.4 Native Method Stacks(本地方法栈)

在这里插入图片描述

4.5 The pc Register (程序计数器)

如果线程正在执行Java方法,则计数器记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的 是Native方法,则这个计数器为空。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值