JVM介绍

什么是JVM ?

一个Java虚拟机;
把Java源码编译成字节码进行运行;

Class文件解析

编译java源文件为class文件:javac User.java->User.class

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html

Class文件格式

Class文件遵循下面结构:

分析Class文件

(1)cafe babe:这是固定的class文件内容开头,代表这是一个class文件

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

(3)0043:constant_pool_count

        The value of the constant_pool_count item is equal to the number of entries in the constant_pool table plus one
        16进制的43等于10进制的67,表示常量池中常量的数量是66

(4)cp_info:constant_pool[constant_pool_count-1]

        The constant_pool is a table of structures representing various string constants, class and interface names, field names, and other constants that are referred to within the ClassFile structure and its substructures. The format of each constant_pool table entry is indicated by its first “tag” byte. 
        The constant_pool table is indexed from 1 to constant_pool_count ‐ 1.|
        字面量:文本字符串,final修饰的常量等
        符号引用:类和接口的全限定名、字段名称和描述符、方法名称和描述符

(5)The constant pool

        官网: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4
        All constant_pool table entries have the following general format:
        

        Table 4.4-A. Constant pool tags

Constant Type Value
CONSTANT_Class 7
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_String 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
CONSTANT_MethodHandle 15
CONSTANT_MethodType 16
CONSTANT_InvokeDynamic 18

(6)u1 tag

        由0a可以知道第一个常量的类型对应的10进制为10,对应上表可知这是一个方法引用CONSTANT_Methodref,查找方法引用对应的 structure
        
        0010对应class_index的十进制为16,0023对应name_and_type_index的十进制为35

(7)u1 info[]

        由08得知十进制为8,对应上表可知是String引用CONSTANT_String,查找对应的 structure
        
        u2 string_index是0024对应十进制是36

反汇编

通过 dk 自带命令 javap -h可以对class文件进行反编译

javap ‐v ‐c ‐p User.class > User.txt 进行反编译,查看字节码信息和指令等信息

JVM相对class文件来说可以理解为是操作系统;class文件相对JVM来说可以理解为是汇编语言或者机 器语言。

类加载机制

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

Loading, Linking, and Initializing, 装载,链接,初始化

Loading

找到Class文件所在的全路径,然后加载到内存中;这个过程使用了类加载器ClassLoader;因为有很多类需要加载,所以用到很多类加载器:大体分为四种:

如果在两个不同的jar中出现两个全路径名字完全相同的类,那么同一个java进程由哪个类加载器去执行呢?为了解决这一问题,所以这里使用双亲委派,每次子类会先递归找到父类,如果父类有就不要子类加载器加载,如果没有,最后再逐级找到子类加载器加载;但是这样就会浪费时间。

所以如果我们确定某个类的全路径独一无二,其他地方不存在,那么我们自定义类加载器去加载,不需要使用双亲委派机制,tomcat就使用了这种自定义类加载器:

class MyClassLoader extends ClassLoader {
    loadClass() {
        // 自定义类加载器加载方法,打破双亲委派模型
    }
}

打破双亲委派模型的方式:

  • (1)重写loadClass方法
  • (2)SPI机制
  • (3)OSGi

Linking

(1)Verification:保证被加载类的正确性

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

(3)Resolution:动态地将运行时常量池中的符号引用转换为直接引用
        常量池:class文件中的constant_pool,保存在磁盘上;
        运行时常量池:是class文件中的constant_pool运行时的表示,保存在内存中;
        符号引用:class文件中的十六进制内容;
        直接引用:十六进制对应的某个变量在物理内存中的某个内存地址;

Initializing

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

JVM运行时数据区

一些数据区随着JVM进程的创建而创建、退出而销毁;其他数据区随着线程的创建而创建、退出而销毁;
进程生命周期:方法区、堆
线程生命周期:Java虚拟机栈、本地方法栈、PC寄存器

方法区

方法区是所有jvm线程共享的内存区域;在jvm启动时被创建;存储每一个类的结构信息,例如运行时常量池、字段、静态变量、方法数据、构造器;
当方法区无法满足内存分配需求时,会抛出OutOfMemoryError异常。

堆是所有jvm线程共享的内存区域;在jvm启动时被创建;堆是jvm所管理内存中最大的一块;java对象实例以及数组都在堆上分配;
堆内存空间不足时,也会抛出OutOfMemoryError异常。

Java虚拟机栈

本地方法栈

PC寄存器


版权声明:本文为luciferlongxu原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/luciferlongxu/article/details/128488833