1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-20 22:17:09 +08:00

Merge pull request #1136 from JoeMinty/patch-4

Update 类加载过程.md
This commit is contained in:
Guide哥 2021-03-25 18:58:51 +08:00 committed by GitHub
commit aee190f094
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -23,7 +23,7 @@
Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚拟机是如何加载这些 Class 文件呢? Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚拟机是如何加载这些 Class 文件呢?
系统加载 Class 类型的文件主要三步:**加载->连接->初始化**。连接过程又可分为三步:**验证->准备->解析**。 系统加载 Class 类型的文件主要三步**加载->连接->初始化**。连接过程又可分为三步:**验证->准备->解析**。
![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/类加载过程.png) ![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/类加载过程.png)
@ -33,7 +33,7 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚
1. 通过全类名获取定义此类的二进制字节流 1. 通过全类名获取定义此类的二进制字节流
2. 将字节流所代表的静态存储结构转换为方法区的运行时数据结构 2. 将字节流所代表的静态存储结构转换为方法区的运行时数据结构
3. 在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口 3. 在内存中生成一个代表该类的 Class 对象作为方法区这些数据的访问入口
虚拟机规范上面这3点并不具体因此是非常灵活的。比如"通过全类名获取定义此类的二进制字节流" 并没有指明具体从哪里获取、怎样获取。比如:比较常见的就是从 ZIP 包中读取日后出现的JAR、EAR、WAR格式的基础、其他文件生成典型应用就是JSP等等。 虚拟机规范上面这3点并不具体因此是非常灵活的。比如"通过全类名获取定义此类的二进制字节流" 并没有指明具体从哪里获取、怎样获取。比如:比较常见的就是从 ZIP 包中读取日后出现的JAR、EAR、WAR格式的基础、其他文件生成典型应用就是JSP等等。
@ -70,7 +70,7 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚
初始化是类加载的最后一步,也是真正执行类中定义的 Java 程序代码(字节码),初始化阶段是执行初始化方法 `<clinit> ()`方法的过程。 初始化是类加载的最后一步,也是真正执行类中定义的 Java 程序代码(字节码),初始化阶段是执行初始化方法 `<clinit> ()`方法的过程。
对于`<clinit>` 方法的调用,虚拟机会自己确保其在多线程环境中的安全性。因为 `<clinit>` 方法是带锁线程安全,所以在多线程环境下进行类初始化的话可能会引起死锁,并且这种死锁很难被发现。 对于`<clinit> ()` 方法的调用,虚拟机会自己确保其在多线程环境中的安全性。因为 `<clinit> ()` 方法是带锁线程安全,所以在多线程环境下进行类初始化的话可能会引起死锁,并且这种死锁很难被发现。
对于初始化阶段虚拟机严格规范了有且只有5种情况下必须对类进行初始化(只有主动去使用类才会初始化类) 对于初始化阶段虚拟机严格规范了有且只有5种情况下必须对类进行初始化(只有主动去使用类才会初始化类)
@ -79,7 +79,7 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚
- 当jvm执行getstatic指令时会初始化类。即程序访问类的静态变量(不是静态常量,常量会被加载到运行时常量池)。 - 当jvm执行getstatic指令时会初始化类。即程序访问类的静态变量(不是静态常量,常量会被加载到运行时常量池)。
- 当jvm执行putstatic指令时会初始化类。即程序给类的静态变量赋值。 - 当jvm执行putstatic指令时会初始化类。即程序给类的静态变量赋值。
- 当jvm执行invokestatic指令时会初始化类。即程序调用类的静态方法。 - 当jvm执行invokestatic指令时会初始化类。即程序调用类的静态方法。
2. 使用 `java.lang.reflect` 包的方法对类进行反射调用时如Class.forname("..."),newInstance()等等。 如果类没初始化,需要触发其初始化。 2. 使用 `java.lang.reflect` 包的方法对类进行反射调用时如Class.forname("..."), newInstance()等等。如果类没初始化,需要触发其初始化。
3. 初始化一个类,如果其父类还未初始化,则先触发该父类的初始化。 3. 初始化一个类,如果其父类还未初始化,则先触发该父类的初始化。
4. 当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main 方法的那个类),虚拟机会先初始化这个类。 4. 当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main 方法的那个类),虚拟机会先初始化这个类。
5. MethodHandle和VarHandle可以看作是轻量级的反射调用机制而要想使用这2个调用 5. MethodHandle和VarHandle可以看作是轻量级的反射调用机制而要想使用这2个调用
@ -100,7 +100,7 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚
所以在JVM生命周期类由jvm自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。 所以在JVM生命周期类由jvm自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。
只要想通一点就好了jdk自带的BootstrapClassLoader,ExtClassLoader,AppClassLoader负责加载jdk提供的类所以它们(类加载器的实例)肯定不会被回收。而我们自定义的类加载器的实例是可以被回收的,所以使用我们自定义加载器加载的类是可以被卸载掉的。 只要想通一点就好了jdk自带的BootstrapClassLoader, ExtClassLoader, AppClassLoader负责加载jdk提供的类所以它们(类加载器的实例)肯定不会被回收。而我们自定义的类加载器的实例是可以被回收的,所以使用我们自定义加载器加载的类是可以被卸载掉的。
**参考** **参考**