垃圾回收方法

回收方法区

在方法区进行垃圾收集的“性价比”一般比较低。永久代的垃圾收集主要回收两部分内容:废弃常量和无用类。(字面量为例)常量池中的一个没有对象引用的常量,也没有其他地方引用了这个字面量,如果这时发生内存回收,而且必要的话,这个常量将会被系统清理出常量池。常量池中的其他类(接口)方法字段的符号引用与此类似。


判定一个类是无用类的三个条件:
1、该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例
2、加载该类的ClassLoader已经被回收
3、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类。


类并不是是无用类就进行回收。是否对类进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class和-XX:+TraceClassLoading,-XX:+TraceClassUnLoading查看类加载和卸载信息。其中-verbose:class和-XX:+TraceClassLoading可以在Product版的虚拟机中使用,-XX:+TraceClassUnLoading参数需要FastDebug版的虚拟机支持。
在频繁自定义ClassLoader的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出。

垃圾回收算法

标记-清除算法
两步:标记,统一回收。最基础的手机算法。
缺点:标记清除两个过程的效率都不高,另一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
复制算法
它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块内存用完了,就将还存活这的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。这样使得每次都是对整个半区惊醒内存回收,内存分配的时候也不用再考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
缺点:将原来的内存缩小为了原来的一半,代价太大。
但是现在的商业虚拟机都采用这种手机算法来回收新生代。
这里写图片描述
当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保。当另一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象时,这些对象将直接通过分配担保机制进入老年代。
标记-整理算法
和“标记-清除”算法一样,但不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。根据老年代特点提出的算法。
分代收集算法
当前商业虚拟机的垃圾收集都采用这种算法。根据对象存货周期的不同将内存划分为几块。一般将java堆分为新生代和老年代,根据各个年代的特点采用最适当的收集算法。新生代(对象存活率低)使用复制算法,老年代(对象存活率高,没有额外空间对它进行分配担保)使用“标记-清理”或者“标记-整理”算法进行回收。

猜你喜欢

转载自blog.csdn.net/hotchange/article/details/79925727