面试题答案
一键面试方法区垃圾回收针对的内容
- 废弃的常量:例如字符串常量池中,若某个字符串常量不再被任何地方引用,就可能成为被回收的对象。比如通过
intern()
方法创建的字符串常量,如果没有其他强引用指向它,可能被回收。 - 不再使用的类型:当类加载器被回收,且该类的所有实例都已被回收,同时该类对应的
Class
对象不再被任何地方引用时,该类的相关元数据(如类的字段、方法、常量池等信息)就可能被回收。
触发方法区垃圾回收的条件
- 对于废弃常量:当常量池中指向常量的引用都被释放,且该常量没有被任何其他地方引用时,便满足了回收条件。
- 对于不再使用的类型:需要同时满足以下三个条件:
- 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
- 加载该类的
ClassLoader
已经被回收。在一些框架使用自定义类加载器时,如果类加载器生命周期结束且不再被引用,就可能满足此条件。 - 该类对应的
java.lang.Class
对象没有在任何地方被引用,即无法通过反射访问该类的方法等。
方法区垃圾回收相较于堆内存垃圾回收的难点和特殊之处
- 判定条件复杂:堆内存中对象的存活判定相对简单,主要基于可达性分析算法,只要对象到 GC Roots 不可达就可能被回收。而方法区中类型的回收需要同时满足多个条件(如上述提到的类相关回收条件),判定更为复杂。
- 回收频率低:方法区中的数据相对稳定,不像堆内存中的对象频繁创建和销毁。例如,类的元数据一旦加载进方法区,在应用运行期间通常不会轻易变化,所以垃圾回收触发频率远低于堆内存。
- 影响范围大:方法区回收类元数据等信息,如果误回收正在使用的类,会导致严重的程序错误,如运行时类找不到等问题。相比之下,堆内存中回收错误对象通常只会影响局部业务逻辑。