方法区中进行垃圾回收的“性价比”一般比较低,在堆中,尤其是在新生代中,常规应用进行一次垃圾收集一般可以回收70%-95%的空间,而永久代的垃圾收集效率远低于此。
永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。回收废弃常量与回收Java堆中的对象非常类似。以常量池中字面量的回收为例,假如一个字符串的
“abc”已经进入常量池中,但是当前系统没有任何一个String对象是叫做“abc”的,换句话说,就是没有任何String对象引用常量池中的“abc”常量,也没余其他地方应用了这个字面量,如果这时发生内存回收,而且必要的话,这个“abc”常量就会被系统清理出常量池。常量池中的其他类(接口),方法,字段的符号引用也与此类似。判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面3个条件才能算是“无用的类”:
1.该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。2.加载该类的ClassLoader已经被回收。3.该类对应的java.lang.Class对象没有在任何地方被引用,无法再任何地方通过反射访问该类的方法。虚拟机可以对满足上述3个无用类进行回收,这个说的仅仅是“可以”,而不是和对象一样,不使用了就必然回收。
对象回收算法:标记-清除算法,复制算法,标记-整理算法,分代收集算法。
分代收集算法:根据对象的存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高,没有额外空间对它进行分配担保,就必须采用“”标记-清除”或"标记-整理"算法来进行回收。