垃圾收集(GC)
如何判断对象已死
1.引用计数算法
在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象时不可能在被使用的。但这个算法很难解决对象之间循环引用的问题。
2可达性分析(根搜索算法)
通过一系列根对象(“GC Roots”)作为起始节点集,根据引用关系向下开始搜索,如果某个对象到GC Roots间没有任何引用链相连(不可达),则证明此对象不可能再被使用。
GC Roots(虚拟机栈中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,被同步锁持有的对象)。
生存还是死亡
真正宣告一个对象死亡,至少要经历两次标记过程:
1.在可达性分析后没有与GC Roots相连接的引用链。
2.第一次标记后进行筛选,筛选此对象是否有必要执行finalize()方法,如果要,该对象被放置在一个名为F-Queue的队列中执行finalize()方法,收集器将对F-Queue中的对象进行第二次标记,如果对象在finalize()中成功拯救自己(只要重新与引用链上任何对象建立关联即可),第二次标记时他将被移出“即将回收”的集合。
垃圾收集算法
1.分代收集理论
1)弱分代假说:绝大多数对象都是朝生夕灭的
2)强分代假说:熬过越多次垃圾收集过程的对象就越难以消灭
3)跨代引用假说:跨代引用相对于同代引用来说仅占极少数
新生代收集(Minor GC):指目标只是新生代的垃圾收集
老年代收集(Major GC):指目标只是老年代的垃圾收集
整堆收集(Full GC):收集整个java堆和方法区的垃圾收集
Eden区:存储了从未通过垃圾收集的新对象
survivor区:存放垃圾回收后,任然有用的对象。循环存放,小于15次垃圾回收次数
Tenured区:老年代区域存放超过15次垃圾回收的对象
2.标记-清除算法
首先标记出所有需要回收的对象(或标记不回收的对象),标记完成后,同一回收所有被标记的对象(不被标记的对象)。
缺点:1.执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是要回收的,这时必须进行大量的标记和清除动作;2.内部空间碎片化问题,标记、清除之后会产生大量不连续的内存碎片。
3.标记-复制算法
将可用的内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块用完了,就将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。
缺点:可用空间缩小为原来的一半。
Appel式回收:把新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次分配只使用Eden和其中一块Survivor。当发生垃圾收集时,将Eden和Survivor中任然存活的对象一次性复制到另外一块Survivor上,然后清理掉Eden和使用过的Survivor。默认Eden和Survivor比例8:1。
4.标记-整理算法(老年代算法)
标记过程于“标记-清除”算法一样,然后让所有存活的对象都向内存空间的一端移动,然后直接清理掉边界以外的内存。
缺点:移动存活对象并更新所有引用这些对象的地方是一种极为负重的操作,必须全程暂停用户应用程序。
算法细节
1.根节点枚举
必须暂停用户线程,枚举期间根节点集合的对象引用关系不能变化。
2.安全点
用户程序要求必须执行到安全点后才能暂停(开始垃圾收集)。
3.安全区域
确保在一段代码片段之中,引用关系不会发生变化。
4.记忆集和卡表
记忆集是一种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构
卡表:记录一块内存区域,该区域内有对象含有跨代指针
5.写屏障
6.并发的可达性分析(用户线程于垃圾收集器线程同时运行)
白色对象:尚未被垃圾收集器访问过
黑色对象:垃圾收集器访问过且所有对象引用已扫描
灰色对象:垃圾收集器访问过且还有对象引用未扫描
满足下面两个条件会发生“对象消失”:
1)插入一条或多条黑色到白色的新引用
2)删除全部灰色到该白色的引用
垃圾收集器
1.Serial
单线程,进行垃圾收集时必须暂停其他所有工作线程。
2.CMS(Concurrent Mark Sweep)
分为四个步骤:
1)初始标记:仅仅标记一下和GC Roots能直接关联到的对象
2)并发标记:从GC Roots直接关联的对象开始遍历整个对象图(不需要停断用户线程)
3)重新标记:修正并发标记期间,因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录
4)并发清除:清除删掉标记阶段已经判断死亡的对象
缺点:
1)对处理器资源非常敏感
2)无法处理“浮动垃圾”
3)产生大量碎片空间
3.G1
开创了收集器面向局部收集的设计思路和基于Region的内存布局形式。
它可以面向对内任何部分来组成回收集进行回收,衡量的标准不是它属于哪个代,而是哪块内存存放的垃圾数量最多。
把连续的Java堆划分成多个大小相等的独立区域,每个Region都可以是Eden,Survivor,老年代空间。Humongous区域专门存储大对象。
G1收集器跟踪各个Region里面的垃圾堆的“价值”大小,价值即回收所获得的空间大小以及回收所需的时间,维护一个优先级列表。
1)初始标记
2)并发标记
3)最终标记
4)筛选回收
4.ZGC