整理自《深入理解java虚拟机》
程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭。而堆和方法区不一样,只有在程序运行期间才能知道会创建哪些对象,这部分的内存和回收都是动态的,垃圾收集器所关注的是这部分内存。
① 判断对象是否已死
a. 引用计数算法
给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就+1,
当引用失效时,计数器值就-1,任何时刻,计数器为0的对象就是不可能再被使用的。
优点:实现简单,判断效率高
缺点:很难解决对象之间互相引用的问题
b. 可达性分析算法
通过一系列的称为“GC Roots”的对象作为起始点,从这些结点开始向下搜索,搜索所走过的路径成为引用链,当一个对象到GC Root没有任何引用链相连时,则证明此对象是不可用的。
② 收集算法
a. 标记—清除算法
首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
缺点:效率不高,清除之后会产生大量不连续的内存碎片
b. 复制算法
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块,当这一块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。
实现简单,运行高效,但是内存缩为了原来的一半。
现在的商业虚拟机都采用这种收集算法来回收新生代。
c. 标记—整理算法
标记出所有需要回收的对象,让所有存活的对象都像一端移动,然后直接清理掉端边界以外的内存。
d. 分代收集算法
当前商业虚拟机的垃圾收集都采用“分代收集”。
根据对象存活周期的不同将内存划分为几块,一般把java堆分为新生代和老年代,在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法。而老年代中因为对象存活率高,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。
③ 垃圾收集器
a. Serial收集器(新生代)
(1)单线程收集器:它在进行时,必须暂停暂停其他所有工作线程(Stop the Word)
(2)虚拟机运行在client模式下的默认新生代收集器
(3)采用复制算法
b. ParNew收集器(新生代)
(1)Serial收集器的多线程版本,回收时会导致stop the world,其他策略和serial一致
(2)运行在server模式下的虚拟机中首选的新生代收集器
(3)采用复制算法
c. Parallel Scavenge收集器(新生代)
(1)此收集器的目标是达到一个可控制的吞吐量。(吞吐量=(运行用户代码时间)/(运行用户代码时间+垃圾收集时间)。高吞吐量则可以高效的利用cpu时间,尽快完成程序运算,主要适合在后台运算而不需要太多的交互任 务。
(2)自适应调节策略:打开开关参数之后,不需要手工指定新生代的大小,eden区和survivor区的比例等细节参数,
虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的
吞吐量。
(3)复制算法,并行多线程收集器
d. Serial Old(老年代)
(1) Serial收集器的老年代版本
(2) 单线程收集器---”标记整理算法“
(3) client模式下虚拟机使用
e. Parallel Old收集器(老年代)
(1) Parallel Scavenge的老年代版本
(2) 使用多线程和”标记-整理“算法
(3) 在注重吞吐量及cpu资源敏感的时候,可以优先考虑
f. CMS(Concurent Mark Sweep)收集器(老年代)
(1) 以获取最短回收停顿时间为目标。
(2) ”标记-清除“算法
(3) 运行过程:初始标记:标记GC Roots能直接关联到的对象,速度很快(stop the world)
并发标记:进行GC Roots Tracing的过程
重新标记:修正并发标记期间因用户线程继续运作而导致标记产生变动的那一部分对象的标记记录
并发清除:
(4) 优点:并发收集,低停顿
(5) 缺点:对cpu资源非常敏感,无法处理浮动垃圾,会有大量空间碎片产生
g. G1收集器(Garbage-First)
(1) 是一款面向服务端应用的垃圾收集器
(2)特点:并行与并发
分代收集:能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时 间、熬过多次GC的旧对象以获取更好的收集效果。
从整体看是基于”标记-整理“算法,从局部(两个Region之间)来看是基于”复制“算法实现的。
可预测的停顿:能够建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段 内,消耗在垃圾收集上的时间不得超过N毫秒。
(3)将整个java堆划分为多个大小相等的独立区域,它可以有计划的避免在整个java堆中进行全区域的垃圾收集。
G1跟踪各个region里面的垃圾堆积的价值大小,在后台维护一个优先列表,每次根据允许的收集时间,优先回
收价值最大的region。
(4)运行过程:初始标记:标记GC Roots能直接关联到的对象
并发标记:进行GC Roots Tracing的过程
最终标记:修正在并发标记期间因用户线程继续运作而导致标记产生变动的那一部分标记记录
筛选回收:对各个region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计 划。