jvm的垃圾收集算法和收集器
垃圾收集算法
标记-清除算法
过程
算法成成2个阶段,"标记"和“清除”两个阶段:首先标记初所有需要回收的对象,在标记完成后统一回收所有被标记的对象。标记的位置在object header中。
应用范围
老年代
不足
效率问题
- 标记和清除的过程的效率都不高。
空间问题
- 标记清除后将会产生大量的的不连续内存碎片,空间碎片太多会导致后面大对象分配时,找不到足够的内存不得不提前触发另一个垃圾回收动作。
复制算法
- 为了解决效率的的问题。
过程
它可以将内存划分为大小相等的两份,每次只使用一块。这块快要满了的将还存活的对象复制到另外一个区域。
应用范围
新生代
优点
- 实现简单效率高 (只需要简单的移动指针,将复制的碎片全部都移到栈顶)
缺点
- 需要牺牲一般的内存做复制,代价非常大
改良
IBM公司研究表明,新生代98%的对象都是“朝生夕死”,所以并不需要按照1:1来划分空间,而是将划分出一大部分Eden区和两块Survivor区(S0、S1虚拟机默认8:1:1),每次回收的时候,都是将Eden区和S0区复制到S1区。
分配担保(Handle Promotion)
- 因为不能保证低于10%存活,如果超过10%存活,那么将导致S1区内存不够,所以需要其他内存(这里指老年代)进行分配担保。
标记-整理算法
过程
与“标记-清除算法”算法相同,但是后续步骤不是直接对标记对象进行清理,而是让向一端移动,然后清理掉端边界意外的内存。
应用范围
老年代
分代收集算法
- 当代虚拟机都采用分级收集算法(Generational Collection)算法。将对象根据存活周期分成几部分。
将java堆分成新生代和老年代。根据不同的年代采用最适当的收集算法。
Serial收集器
- Serial收集器最近本的、发展历史最悠久的收集器,曾经(在JDK1.3.1之前是虚拟机新生代的唯一选择)
优点
- 简单高效(与其他收集器的单线程相比),对于单个CPU的环境的来说,Serial收集器由于没有线程交互的开销,可以获得最高的单线程收集效果。
缺点
- 单线成收集器,因为了垃圾收集-垃圾回收时必须暂停所有用户进程(Stop The World),会倒追计算机每运行1小时暂停5分钟。
参数
- -XX:+ServivorRatio
- -XX:+PretenureSizeThreshold
- -XX:+HandlePromotionFailure
ParNew收集器
- ParNew是Serial收集器的多线程版本。目前只能与CMS收集器合作
参数
- -XX:+ServivorRatio
- -XX:+PretenureSizeThreshold
- -XX:+HandlePromotionFailure
- -XX:+UseParNewGC 指定ParNewGC回收器
Parallel Scavaenge收集器
- Parallel Scavaenge收集器是一个关注与
吞吐量(Throughput)
多线程收集器。 - 这里的吞吐量 = (运行用户代码时间)/(运行用户代码时间+垃圾收集时间) 。是一个比值。
参数
- -XX:MaxGCPauseMillis 大于0的毫秒数,收集器将尽可能保证内存回收话费的时间不超过设定值。
- -XX:GCTimeRatio 介于0到100的整数,垃圾收集时间占总时间的比率。
- -XX:+UseAdaptiveSizePolicy的开关参数。不需要手工指定新生代的大小(-Xmn),Eden和Servivor区的曲率(-XX:ServivorRatio),晋升老年代对象大小(-XX:PretenureSizeThreshold)
Serial Old收集器
- Serial Old收集器是Serial收集器的老年代版本,它同样是一个单线程收集器,使用的“标记-整理”算法。
Parallel Old收集器
- Parallel Old收集器是Parallel Scavaenge收集器 老年版本,使用多线程和“标记-整理”算法。
CMS收集器
- CMS(Concurrent Mark Sweep)收集器是一中最短回收停顿时间为目标的收集器。
过程
初始标记(CMS initial mark)
并发标记(CMS concurrent mark)
重新标记(CMS remark)
并发清除(CMS concurrent sweep)
- 其中,初始标记、并发标记这两个步骤仍然需要“Stop The World”。
- 初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快。
- 并发标记阶段进行GC Roots Tracing的过程。
- 重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致变动的那一部分继续,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记时间端。
由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以你,从总体上说CMS收集器的内存回收过程是与用户线程一起并发执行的。
缺点
CMS收集器对CPU资源非常敏感。
- CMS默认回收线程数(CPU数量+3)/4,当CPU不足4个时,CMS对用户程序影响很大。当CPU大于4个时,并发回收时垃圾不少于25%的系统资源,并且随着CPU数量增加而下降。
CMS收集器无法处理浮动垃圾(Floating Garbage)。
-
浮动垃圾
因为CMS并发清理阶段依旧有用户线程在运行,也会产生垃圾,这部分垃圾称为浮动垃圾。 - 浮动垃圾只能在下次GC的时候处理。
- 可能会出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。
- 所以不能在100%时开始垃圾回收。
解决办法
- 提供了* -XX:CMSInitiatingOccupancyFraction的值来提高阈值
CMS是给予“标记-清除”的收集器,会产生大量碎片。
解决办法
- CMS提供来一个-XX:+UseCMSCompactAtFullCollection开关参数(默认开启状态),用于在CMS收集器顶不住要Full GC的时候,启用合并整理。
- 但是时间会变长,CMS另外提供一个参数-XX:CMSFullGcsBeforeCompaction(默认0),用于设置执行多少次不“标记压缩”之后执行一次“标记压缩”。
G1收集器
- G1(Garbage-first)收集器是当今收集器技术发展的最前沿成功之一。在JDK7u4,Sun公司认为达到足够商用成都,移除了“Experimental”标示。
特点
并发与并行。
- G1能充分利用多CPU,多核环境下的硬件优势,使用多个CPU来缩短STW时间。
分代收集
- G1可以不需要其他收集器配合就能独立管理整个GC堆。
空间整合
- G1整体是基于“标记-整理”算法实现的收集器。从局部(两个Region之间)上来看是基于”复制“算法实现的。
- 这两种都不会产生内存碎片。
可预测的停顿
内存分配和回收策略
对象优先在Eden区分配
- 虚拟机默认在Eden区进行分配
大对象直接进入老年代
- -XX:PretenureSizeThreshold参数,大于这个设置值的参数会直接进入老年代,目的是可以避免在Eden区和Survivor区之间发生大量的内存复制。 PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效。
长期存活的对象将进入老年代
- -XX:MaxTenuringThreshold(默认15岁)* 每熬过一次Minor GC,年龄增加一岁。大概该设置的参数值,将进入老年代。
空间分配担保
- 在发生Minor GC之前,虚拟机会检查老年代
最大可用的连续空间是否大于新生代的所有对象总空间
,如果条件成立,那么Minor GC可以确保是安全的
。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可以用的连续空间是否大于历次晋升到老年代的平均大小,如果大于,那么将尝试着一次MinorGC,仅管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那这是也要改为进行一次Full GC。