JVM类加载子系统

46 阅读3分钟

1.JVM内存结构

第02章_JVM架构-简图.jpg

第02章_JVM架构-英.jpg

由上图可知,类加载过程:加载--->链接--->实例化

如果想手写一个Java虚拟机,类加载子系统和执行引擎必须。

2.类的加载过程

第02章_类的加载过程.jpg

类加载只是将对应的字节码文件加载到内存之中,能不能执行还是得看执行引擎

1.loading

根据全限定名获取字节的二进制流,将其中的静态存储结构转化为方法去的数据,生成class作为获取方法区数据的入口

加载的类的来源

  1. 从本地文件直接获取
  2. 从网络上获取
  3. 通过jar包之类的获取
  4. 运行时计算生成,动态代理技术

Linking

  1. 判断字节码有没有错
  2. 将其中的一些数据,常量数据初始化
  3. 解析,将一些符号解析为操作

init

  1. 执行类构造器方法clinit()。
  2. 这个是javac编译器自带的,就是把类中所有的静态初始化方法(包括静态代码块里的)合并执行,
  3. 顺序就是代码写的顺序。
  4. clinit在多线程时会被加锁,保证只加载一次(加载一次,把数据放入方法区)

实例化案例.png

在这个案例里,number在linking阶段就赋值为0了,所以在这里先变成20,再覆盖为10

几种类加载器

1.启动类加载器(引导类加载器)

  1. 使用c++写的,参套在jvm内部
  2. 用来加载jvm里面的核心类库,本身没有父类
  3. 因此加载扩展类加载器那些并指定他们的父加载器
  4. 识别Java,Javax,sun开头的这些

2.扩展类加载器

  1. 用Java写的
  2. 加载的是除了Java核心的类库之外用户扩展引入的类

3.系统类加载器

  1. 用Java写的
  2. 加载扩展类加载器加载出的那些类。(一个核心类库里会有很多的类,系统类就是加载具体的那些类)

4.用户自定义类加载器

一般用上面三种就够了,有时候需要自定义类加载器:

什么时候需要

  1. 隔离加载类,有时候需要一个类与其他的类之间不产生联系和冲突
  2. 修改类的加载方式

双亲委派机制

双亲委派机制.png

  1. 一个类加载器收到了类加载请求,他会向父类加载器委托,一直到启动类加载器
  2. 当父类加载器发现这个包不归自己管的时候就向下分派,一直到能加载为止

疑问:

1.为什么是双亲?

双亲应该是站在系统类加载器的角度,他有两个父类

2.为什么收到加载请求后,不一开始就直接委托给启动类,而是一层一层

默认的时系统类加载器,这样设计我感觉时因为使用递归去调,可以记录下这一层是什么加载器,一开始直接用引导类,他就不知道该分派给谁,所以就默认为系统类加载器。

3.为什么一定要传到引导类加载器

安全性问题吧,如果在这一层和父类那一层都有相同的类的话,可能会影响父类加载器里的一些库的实现,造成安全性问题。(比如Java核心类库都在引导类,但是如果在自定义类创建了一个类名相同的,不去委派到引导类加载器,就会影响实现(这一部分就是沙箱安全机制))

其他

除了启动类加载器之外,其他的类加载器除了将数据保存在方法区,还会把这个类加载器的一个引用保存在方法区,去表示我引用的是这个类加载器,做一个区分