jvm类加载过程总结

参考javaguide(guide哥的原文链接)

类加载的生命周期

类加载过程?

加载->连接->初始化->使用->卸载

image-20211022210215946

加载

  1. 通过全类名获取定义该类的二进制字节流
  2. 将字节流所代表的静态存储结构转换为方法区的运行时结构
  3. 在内存生成一个代表该类的class对象,作为方法区这些数据的方法入口

验证

验证字节码文件各种信息

  1. 文件格式,版本号,常量池是否支持
  2. 元数据验证:字节码描述信息,类等各种继承信息
  3. 字节码验证:字节码验证
  4. 符号引用验证

准备

分配内存,并且设定初始值

  1. 分配类变量但是不包括实例变量(在java堆中会处理)
  2. 静态变量(jdk7之后把静态变量和字符串常量池都放到了堆)和class对象被放到堆中
  3. 赋值给类变量为0除非是final+static那么就是赋值常量的值

解析

  • 相当于即使把符号引用解析为直接引用
  • 比如调用一个方法,但是符号引用是不知道那个位置的,系统需要知道位置在哪就会制造一张表存储类的所有方法位置,那么符号引用可以直接解析到方法在什么位置。比如有的类在其他文件你无法看到,那么只能是符号引用,只有通过解析,把类的位置注册到表中,那么就能够知道类的位置给符号引用赋值。

初始化

cinit实际上就是给静态变量赋值

new、 getstatic、putstatic、invokestatic

  • new指令会创建一个对象初始化类
  • getstatic初始化一个类,可以访问静态变量
  • putstatic初始化类给类的静态变量赋值
  • invokestatic初始化类调用静态方法
  • Class.forName和newInstance反射可以初始化类
  • MethodHandle和varHandle轻量级反射机制,需要先调用findStaticVarHandle来初始化类
  • 默认方法也会初始化类

最后就是卸载类

  • 类的对象都被gc了
  • 该类没有在其他地方被引用
  • 该类的类加载器实例已经被gc

双亲委派的好处?

  • 避免类重复加载,被不同的类加载器加载就是不同的类
  • 保证核心api不被修改

如果不想打破双亲委派?

  • 重写findClass

  • 如果想要打破那么就重写loadClass,因为loadClass源码就是在不断往上找父类的classLoader先加载其它类

  • 如果想要打破那么就重写loadClass,因为loadClass源码就是在不断往上找父类的classLoader先加载其它类

猜你喜欢

转载自blog.csdn.net/m0_46388866/article/details/120916920