0
点赞
收藏
分享

微信扫一扫

01-​JVM学习记录-类加载器

绪风 04-07 14:00 阅读 0

 一、类加载器子系统

1. 作用-运输工具(快递员)

2. 类的加载过程

2.1 加载

加载是类加载过程的一个阶段,注意区分
        1. 通过一个类的全限定名获取定义此类的二进制字节流
        2. 将这个字节流所代表的的静态存储结果转化为方法区的运行时数据结构
        3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口

2.2 链接

2.2.1 验证:确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全
2.2.2 准备:为类变量分配内存,并且设置该类变量的初始值,即零值

不包含用final修饰的static(常量),在编译的时候就会分配了,准备阶段会显示初始化

不会为实例变量分配初始化(还没创建对象),类变量会分配在方法区中,实例变量会随着对象一起分配到Java堆中

2.2.3 解析

符号引用是用符号(如类名,方法名,字段名等)来描述所引用的对象,而直接引用是用具体的内存地址或指针来指向所引用的对象。符号引用在编译阶段就存在,但是需要在运行时通过类加载器解析成直接引用。直接引用在运行时才存在,它可以直接定位到内存中的目标。直接引用的效率要比符号引用高。 

2.3 初始化

        初始化阶段是执行类构造器方法<clinit>()的过程,此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。如果没有类变量和静态代码块,也不会有clinit。构造器方法中指令按照语句在源文中出现的顺序执行。
  • <clinit>()不同于类的构造器(关联:构造器是虚拟机视角下的<init>())
  • 非法的前向引用:可以在static中对number先赋值,再声明,但不能先调用。

  • 若该类具有父类,JVM会保证子类的<clinit>()执行前,父类的<clinit>()已经执行完毕

  • 虚拟机必须保证一个类的<clinit>()方法在多线程下被同步加锁,只被执行一次
  • Java虚拟机规范严格规定了,有且只有六种情况,必须立即对类进行初始化,其他使用类的方式被看做是对类的被动使用,都不会导致类的初始化

3. 类加载器分类

        分为引导(启动)类加载器和自定义加载器(所有派生于抽象类ClassLoader的类加载器都划分为自定义加载器,扩展类加载器和系统类加载器属于自定义加载器)。

  • 引导类加载器返回null,获取不到(因为是c/c++写的),系统的核心类库都是用引导类加载器。
  • 自定义类加载器默认使用系统类加载器

3.1 引导类加载器

  • C/C++语言实现,嵌套JVM内部,用来加载Java核心类库,rt.jar、resources.jar、sun.boot.class.path路径下的内容。

  • 并不继承java.lang.ClassLoader,没有父加载器,是扩展类和应用程序类加载器的父加载器。
  • 出于安全考虑,Bootstrap启动类加载器只加载包名为java\javax\sun等开头的类

3.2 扩展类加载器

  • Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
  • 派生于ClassLoader类
  • 父类加载器为启动类加载器
  • 从java.ext.dirs系统属性所指定的目录中加载类库,或从jre/lib/ext子目录下加载类库。如果用户创建的jar放在此目录下,自动由扩展类加载器加载。

3.3 系统类加载器(应用程序类加载器)

  • Java语言编写,由sun.misc.Launcher$AppClassLoader实现
  • 派生于ClassLoader类
  • 父类加载器为扩展类加载器
  • 负责加载环境变量classpath或系统属性java.class.path指定路径下的类库
  • 该类加载器是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载
  • 通过ClassLoader#getSystemClassLoader()方法可以后去到类加载器

3.4 用户自定义类加载器

3.4.1 为什么要用自定义类加载器?
3.4.2 实现步骤

3.5 ClassLoader

抽象类,除了启动类加载器,其他类加载器都继承于此。

findClass方法中调用defineClass方法,搭配使用。
获取ClassLoader的途径:

4. 双亲委派机制

1. 一种任务委派模式:

JVM对Class文件采用的是按需加载(需要使用该类时才将它的class文件加载到内存生成class对象),而且加载class文件时,Java虚拟机使用的是双亲委派模式,即把请求交由父类处理。

例:如果我自定义了一个包java.lang,写了一个String类,默认是系统类加载器,我在其他类的静态代码块使用String,加载时不会加载我写的String类,依然是引导类加载器,因为引导类加载器是系统类加载器的父加载器(扩展类加载器)的父加载器,且可以完成这个加载任务。

2. 优势

  • 避免类的重复加载
  • 保护程序安全,防止核心API被篡改

3. 沙箱安全机制

  • 保证对Java核心源代码的保护
 例:360沙箱,将一些东西(U盘、病毒)限制在沙箱区域里运行,不会影响电脑的其他程序。

5. 类的主动使用和被动使用

参考:b站尚硅谷-宋少康

举报

相关推荐

0 条评论