方法区的内存回收目标主要是针对 **常量池的回收 和 对类型的卸载**
回收废弃常量与回收Java堆中的对象非常类似
以常量池中字面量的回收为例
假如一个字符串“abc”已经进入了常量池中 但是当前系统没有任何String对象引用常量池中的“abc”常量 也没有其他地方引用了这个字面量
如果在这时候发生内存回收 而且必要的话 这个“abc”常量就会被系统“请”出常量池
常量池中的其他类(接口)、方法、字段的符号引用也与此类似
判定一个常量是否是“废弃常量”比较简单
而要判定一个类是否是“无用的类”的条件则相对苛刻许多
类需要同时满足下面3个条件才能算是“无用的类”:
1)该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例
2)加载该类的ClassLoader已经被回收
3)该类对应的 java.lang.Class 对象没有在任何地方被引用 无法在任何地方通过反射访问该类的方法
虚拟机可以对满足上述3个条件的无用类进行回收(卸载)
这里说的仅仅是“可以” 而不是和对象一样 不使用了就必然会回收
特别地 在大量使用反射、动态代理、CGLib等bytecode框架的场景 以及动态生成JSP和OSGi这类频繁自定义ClassLoader的场景都需要虚拟机具备类卸载的功能 以保证元空间不会溢出