JVM是用来做啥的(二)

68 阅读2分钟

一、类加载⼦系统

企业微信截图_20230705115515.png

  • 类加载⼦系统会将某个class⽂件加载到⽅法区的内存空间中,可以理解为把class⽂件中字节码指
  • 令,读取到内存中。
  • 验证阶段会验证待加载的class⽂件是否正确,⽐如验证⽂件格式
  • 准备阶段会为static变量分配内存并赋零值
  • 解析阶段会将符号引⽤解析为直接引⽤,在⼀个字节码⽂件中,会⽤到其他类,⽽在字节码中只会
  • 存⽤到的类的类名,⽽解析阶段就是会根据类名找到该类加载后在⽅法区中的地址,也就是直接引
  • ⽤,并替换调符号引⽤,这样真正运⾏字节码时,就能直接找到某个类了。
  • 初始化阶段会给static变量赋值,并执⾏static块

二、类加载器的分类

企业微信截图_20230705120507.png

在JVM规范中,把类加载器分了两种:

  • ⼀种是BootStrapClassLoader,这是由C和C++实现的,负责加载jre/lib下的jar包中的类,⽐如
  • rt.jar中的String类
  • ⼀种是继承了ClassLoader抽象类的类加载器,是由Java语⾔实现的,⽐如:
    • ExtClassLoader,⽤Java实现的,加载⽬录为jre/lib/ext⽬录下的类,可以看下Launcher类中的代码
    • AppClassLoader,⽤Java实现的,加载⽬录为classpath所指定的⽬录,可以看下Launcher类中的代码
    • 以及其他⾃定义的,⽐如Tomcat中的WebAppClassLoader

⽐如在Launcher类中有两个静态内部类:

static class AppClassLoader extends URLClassLoader {

// ...

}

static class ExtClassLoader extends URLClassLoader {

// ...

}

image.png

通过继承URLClassLoader,最终间接继承了ClassLoader。

三、双亲委派

企业微信截图_20230705133150.png

直接看代码:

image.png

image.png

image.png

这段代码就体现了双亲委派,通常我们⽤AppClassLoader去加载⼀个类时,AppClassLoader有⼀个 parent属性指向了ExtClassLoader,当我们⽤AppClassLoader去加载⼀个类时,会先委托给 ExtClassLoader去加载,⽽ExtClassLoader没有parent属性,所以会委派给BootstrapClassLoader去加 载,只有BootstrapClassLoader没有加载到,才会由ExtClassLoader去加载,也只有ExtClassLoader 没有加载到,才会由AppClassLoader来加载,这就是双亲委派。

双亲委派的优点:

  • 避免类的重复加载,如果⼀个类被BootStrapClassLoader加载过了,那么AppClassLoader就不会 再重复加载到这个类了。
  • 防⽌核⼼API被篡改,⾃定义⼀个java.lang.String类,但是我们是不到这个类的,因为根据双亲委派 始终加载的都是rt.jar中的java.lang.String类

后续写Tomcat为什么要⾃定义类加载器?运⾏时数据区