java GC

对象存活判定

引用计数算法

给对象一个引用计数器,当有引用指向该对象时,计数器加1。当引用断开时,计数器减1

如果计数器为0,那么就代表该对象为垃圾,需要对其回收。

缺陷:无法解决循环引用的问题

存在两个失去引用的对象aba中有一个引用成员指向了b,而b中也有一个引用成员指向了a。致使,虽然ab都是垃圾,但是它们的引用计数器不为0。导致无法被回收。

可达性分析算法

通过一系列的GC Roots 对象作为起始点,从这些节点开始往下搜索,搜索所走过的路径称为Reference(引用链)。当对象到GC Roots没有任何引用链相连时(就是从GC Roots到这个对象不可达),则证明此对象是不可用的。

可以作为GC Roots的对象:

* 虚拟机栈中的引用对象。

* 方法区中类静态属性引用的对象。

* 方法区中常量引用的对象。

* 本地方法栈JNINative方法)引用的对象。

引用

Strong Reference:

只要强引用存在,垃圾回收器永远都不会回收掉被引用的对象。

Soft Reference

用来描述还有用,但不必须的对象。在JVM将要发生内存溢出之前,会对这种引用进行二次回收。如果回收后,还是没有足够的内存,才会抛出溢出。

Weak Reference

用来描述非必须的引用,强度比软引用更弱。弱引用只能生存在下一次垃圾收集之前,当垃圾收集器工作时,不管内存是否足够,都会被释放。

Phantom Reference

无法通过一个虚引用取得对象实例。之所以要有虚引用,是因为这个引用被回收时会收到一个系统通知。

垃圾回收算法

标记-清除算法

首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

缺点:

标记和清除效率都不高。

标记清除之后会产生大量不连续的内存碎片,导致以后在分配较大的对象时,因无法找到连续的内存而不得不提前触发另一次垃圾收集工作。

复制算法

把可用内存分为大小相等的两块,每次只使用其中一块。当这一块内存用完了,就将还存活的对象复制到另一块上面,然后在把使用过的内存空间一次释放掉。
优点:

1)每次只对半个区进行垃圾回收

2)不用考虑内存碎片等复杂情况

3)只需移动堆顶指针,按顺序分配内存,运行高效,实现简单。

缺点:内存缩小一半,代价高昂。

普遍用这种算法回收新生代。因为其中的对象98%生命周期非常短暂,所以并不需要按1:1划分内存。

将内存分为较大的EdenSurvivor空间。每次使用其中的Eden和其中一块Survivor。当回收时,将EdenSurvivor中存活的对象一次性的复制到另一块Survivor中,最后清理掉用过的EdenSurvivor

HotSpot默认EdenSurvivor大小为:8:1

分配担保机制:

当另一块Survivor不够存放上一次收集下来的存活对象时,这些对象通过分配担保机制直接进入老年代。

新生代:其中大多数对象都是“朝生夕死”。

标记-整理算法

    复制法应当对象存活率比较低的情况。而对于老年代就十分不适合。

和标记清除法一样先标记要清除的对象,然后不是直接清除,而是让所有存活的对象都向一端移动,从而清理内存。

分代收集算法

    根据对象的存活周期将对象划分为几块,一般是把堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适合的算法。新生代使用复制算法,老年代中使用标记整理算法或标记清除算法。

 

原文地址:https://www.cnblogs.com/holos/p/6622028.html