类的卸载是Java虚拟机将类的Class对象及其对应的二进制数据从方法区中移除的过程。
类的卸载主要发生在两个时机:
- 垃圾收集时:如果类的Class对象没有任何引用指向,则会被垃圾收集器回收,导致该类被卸载。
- 程序退出时:Java虚拟机退出时会卸载所有的类。
类的卸载过程如下:
- 类的Class对象没有任何引用时,会被标记为不可达的,可以被垃圾收集。
- 垃圾收集器回收不可达的Class对象。
- 虚拟机检查该Class对象是否还属于任何其它对象的引用路径。如果没有,则可以将其卸载。
- 虚拟机执行类的 unload 方法,将其类信息,常量池等从方法区中清除。
- 类的字节码文件仍然保留在磁盘中,可以在以后重新加载。
需要注意的是,类的卸载不会影响该类的已实例化对象,这些对象依然可以正常使用。只不过,随着这些对象的逐渐消失,该类的影响也会逐渐减小。
来看一个简单例子:
public class UnloadingDemo {
public static void main(String[] args) {
Son s = new Son();
s = null; // Son类的引用设置为null
// 手动触发垃圾收集
System.gc();
// Son类是否已经被卸载
System.out.println(Son.class);
}
}
class Son {}
在上述程序中:
- 新创建Son类的实例s,Son类会被加载到内存中。
- s引用设置为null,Son类的Class对象变为不可达。
- 执行System.gc()后,Son类的Class对象会被垃圾收集器回收。
- 由于Son类没有其它引用,会被虚拟机卸载,Class对象也会被清除。
- 所以打印Son.class会抛出NoClassDefFoundError错误。