序言:
1.什么是JVM?
- JVM就是将javac编译后的.class字节码文件翻译为操作系统能执行的机器指令
- 翻译过程:
- 前端编译:生成.class文件就是前端编译
- 后端编译:通过jvm解释(或即时编译或AOT)执行
- .class文件时跨平台的,jvm并不是跨平台的
- 通过javap进行反编译
2.java文件是怎么变成.class文件的?
属于前端编译
3..class文件解读
- 采用16进制
- magic、版本号、常量池(包括字面量、符号引用、接口、字段、方法等)、字段表集合、方法表集合
- 符号引用就是类信息、修饰符、名称等
4.类加载机制(JVM的类加载子系统)
- 所谓的类加载机制就是将class文件加载进内存,并对数据进行校验,转换解析和初始化,使得JVM可以直接使用。
- 如何加载进内存?
- 常见的从本地系统加载
- 动态代理
- 从jar包加载
- 类加载过程
- 装载:
- 通过类全限定名获取类的二进制字节流!这个过程可以做拦截增强
- 将字节流代表的静态存储结构转换为方法区的运行时数据结构
- 在堆中生成java.lang.class对象,作为对方法区中这些数据的访问入口(defineClass方法生成)
- 链接
- 验证:格式验证、字节码验证:跳转验证、符号引用验证、元数据验证:语法。-Xverify:none 取消验证。穿插在整个过程中
- 准备:为静态变量赋值,初始化成默认值。
- 这里不包含final修饰的static,final修饰的static都在编译的时候就分配了
- 不会为实例变量分配初始化,类变量在方法区中,实例变量随着对象在堆中(即在实例构造器方法中进行的)
- 解析
- 将符号引用(名称、描述符、全限定名啥的)转换成直接引用,直接指向目标的指针(方法区里的指向)
- 对解析结果进行缓存
- 初始化
- 对比于准备阶段,这里是通过指定主观计划去初始化变量和其他资源。有点懒加载的味道,需要使用的时候才加载
- 对类变量设置初始值的两种方式:
- 直接声明
- static代码块
- 步骤
- 先装载和链接本类
- 然后初始化父类
- 初始化自己
- 什么时候加载(初始化):(主动引用)
- 创建实例;final在调用构造方法前就要弄好
- 使用静态变量或者静态方法的时候
- 调用子类父类也会初始化;
- 标明启动类的类,或者像object和class类启动时候就加载了
- 反射的时候
- (被动引用)
- 定义类数组不会初始化
- 使用父类的静态变量,不会初始化
- 使用static final不会初始化
- 卸载:
- 用完之后就卸载回收
- 所有实例被回收,classloader被gc回收,class对象没有被任何地方引用
- 装载:
5.类加载器
- 类加载器:
- 就是读取字节码,转换成java.lang.class类的一个实例的代码模块
- 一个类在同一个类加载器中具有唯一性,不同类加载器是允许同名类存在的,类加载器不同,就不会是同一个类。
- 分类:
- Bootstrap classloader:负责java_home的所有class,核心类库
- Platform classloader:负责一些扩展的包
- Application classloader:classpath中指定的包
- custom classloader:根据程序自定义类加载器
- 为什么要分层?
- 如果自己编写了一个String类,如果只有一个的话无法判定究竟要加载哪个。所以分层对信任级别进行划分
- 即使打破了双亲委派也不能重写String,defineClass限制了限定类名不能以java开头,除非自己将二进制流转换成class对象
- 三个特性:
- 全盘负责:
- 当一个类加载器加载某个class的时候,该class所依赖的和引用其他的class都由该类加载器负责载入。除非显式使用另一个类加载器
- 父类委托(双亲委派):
- 首先传入类的全限定名
- 为什么:实现带有优先级的层次关系
- 从app层依次往上找是否加载过,然后又从上往下看谁能加载,最后还没有就抛异常。
- 可以重写loadclass打破双亲委派
- 打破:
- SPI,JDK提供了一套接口,定义实现类,在META-INF/services中注册实现类的相关信息,比如JDBC的DriverManager
- OSGI:热部署、热替换
- 如果怕打破可以重写findclass方法
- 缓存机制:
- 加载过的class文件在内存中(方法区)缓存
- 每一个类加载器都有自己的缓存
- 打破父类委托:
import java.io.IOException; import java.io.InputStream; public class CustomClassLoader extends ClassLoader { public CustomClassLoader(ClassLoader parent) { super(par
- 全盘负责: