《深入理解Java虚拟机》2.垃圾回收_回收方法区

回收方法区

有些人认为方法区(如HotSpot虚拟机中的元空间(MetaSpace)或者永久代)是没有垃圾回收的,《Java虚拟机规范》中提到过可以不要求虚拟机在方法区中实现垃圾收集,事实上也确实有未实现或未能完整实现方法区类型卸载的收集器存在(如JDK11时期的ZGC收集器就不支持类的卸载),方法区的垃圾收集的"性价比"通常也是比较低的,在Java堆中,尤其是在新生代中,对常规应用进行一次垃圾收集通常可以回收70%-99%的内存空间,相比之下,方法区回收由于苛刻的判定条件,其区域垃圾收集的回收成果远远低于此。

方法区的垃圾收集主要回收两部分内容,废弃的常量不再使用的类型

举个常量池中字面量回收的例子,假如一个字符串“java”曾经进入常量池中,但是当前系统又没有任何一个字符串对象的值是“java”,换句话说,已经没有任何字符串对象引用常量池中的“java”常量,且虚拟机中也没有其他地方引用这个字面量。如果在这时发生内存回收,而且垃圾收集器判断确有必要的话,这个“java”常量就将会被系统清理出常量池。常量池中其他类(接口)、方法、字段的符号引用也与此类似。

判断一个常量是否"废弃"还是相对简单,而要判定一个类型是否属于"不再被使用的类"的条件就比较苛刻,需要同时满足下面三个条件。

  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例
  • 加载该类类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGI,JSP的冲加载等,否则通常是很难达成的。
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

结语

在大量使用反射、动态代理、CGLib等字节码框架,动态生成JSP以及OSGI这类频繁自定义类加载器的场景中,通常都需要Java虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的压力

猜你喜欢

转载自blog.csdn.net/qq_46312987/article/details/121087786