文章目录
一、JVM
- 源码到类文件
- 类文件到JVM
- JVM各种折腾(内部结构、执行方式、垃圾回收、本地调用等)
1.1 源码到类文件
1.1.1 源码demo
编译:类名.java —> 类名.class
1.1.2 前期编译
类名.java -> 词法分析器 -> tokens流 -> 语法分析器 -> 语法树/抽象语法树 -> 语义分析器 -> 注解抽象语法树 -> 字节码生成器 -> 类名.class文件
1.1.3 类文件(Class文件)
1.1.3.1 16进制
1.1.3.2 文件结构
一个class文件由一个ClassFile组成
1.1.3.3 简单分析
参考上文中的16进制文件来分析,每两个数字为一个u1
- u4:cafe babe,代表的就是magic
- u2 + u2:0000 + 0034,转化为10进制为52,表示的是JDK8
- u2:003f,转化为10进制为63,表示常量池中的数量为62(其值为常量池中常量数 + 1)
常量池主要存储两方面内容:
字面量(Literal):文本字符串,final修饰等
符号引用(Symbolic References):类和接口的全限定名、字符名称和描述符、方法名称和描述符
JVM相对class文件来说可以理解为是操作系统;class文件相对于JVM来说可以理解为是汇编语言或者机器语言
1.1.3.4 常量池分析
上面说到常量池中常量的数量是62,现在来具体分析这62个常量,也就是cp_info constant_pool[constant_pool_count - 1]的信息,cp_info其实是一个表格的形式,表中的每个条目都具有以下的通用格式:
tag是该条目的标签,其如下
我们接着分析前面的16进制数据,已经分析到了003f,现在开始分析其后面的数据
- 往下数一个u1,即0a -> 10,代表的是CONSTANT_Methodref,表示这是一个方法引用,其info如下:
还需要往下数两个u2
- u2:即00 0a -> 10,代表的是class_index,表示该方法所属的类在常量池中的索引
- u2:即00 2b -> 43:代表的是name_and_type_index,代表该方法的名称和类型的索引
-
再往下数u1,即08 -> 8:表示的是CONSTANT_String,表示字符串类型
往下数一个u2
- u2:即00 2c -> 44,代表的是string_index
-
往下数一个u1,即09 -> 9,表示的是CONSTANT_Fieldref,表示字段类
往下数u2和u2- u2,即00 0d -> 13:代表的是class_index
- u2,即00 2d -> 45:代表的是name_and_type_index
2.2 类文件到虚拟机(类加载机制)
所谓类加载就是:
- 虚拟机把Class文件加载到内存
- 并对数据进行校验,转换解析和初始化
- 形成虚拟机可以直接使用的Java类型,即java.lang.Class
2.2.1 装载(Load)
查找和导入class文件
- 通过一个类的全限定名获取定义此类的二进制字节流(需要借助于类加载器)
- 将这个字节流代表的静态存储结构转化为方法区的运行时数据结构
- 在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口
2.2.2 链接(Link)
2.2.2.1 验证(Vertify)
保证被加载类的正确性
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
2.2.2.2 准备(Prepare)
为类的静态变量分配内存,并将其初始化为默认值
2.2.2.3 解析(Resolve)
把类中的符号引用转换为直接引用
符号引用就是一组符号来描述目标,可以说任何字面量
直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄,换句话说就是其内存地址
解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行
2.2.3 初始化(Initialize)
对类的静态变量,静态代码块执行初始化操作
2.2.4 类加载器ClassLoader
就是用来装载Class文件的
2.2.4.1 分类
- Bootstrap ClassLoader:负责加载 $JAVA_HOME 中的 jre/lib/rt.jar 里的所有class或Xbootclassoath选项指定的jar包
- Extension ClassLoader:负责加载java平台中扩展功能的一些jar包,包括 $JAVA_HOME 中 jre/lib/*.jar 或 -Djava.ext.dirs 指定目录下的jar包
- App ClassLoader:负责加载classpath中指定的jar包及 Djava.class.path 所指定目录下的类和jar包
- Custom ClassLoader:通过java.lang.ClassLoader的子类自定义加载class,属于应用程序根据自身需要自定义的ClassLoader
2.2.4.2 图解
2.2.4.3 加载原则[双亲委派]
-
检查某个类是否已经加载
自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个Classloader已加
载,就视为已加载此类,保证此类只所有ClassLoader加载一次
-
加载的顺序
自顶向下,也就是由上层来逐层尝试加载此类
2.2.4.4 破坏双亲委派
- tomcat
- SPI机制
- OSGi