JVM垃圾收集器
jdk1.7之后HotSpot虚拟机中提供了商用的G1收集器,之前都是实验状态
垃圾回收中的并发编程中的概念
并发:用户线程和垃圾收集线程同时进行,用户进程在继续进行,而垃圾回收线程运行于另外一个CPU
并行:指的是多条垃圾收集线程同时工作,但是用户线程在等待
Serial收集器
这个收集器最大点特点除了是通过一个cpu或一条收集线程完成垃圾收集工作以外,还必须暂停掉其他所有工作的线程直至它收集完成
由于单线程的运行机制,简单高效。在限定的单cpu的环境中,没有线程交互的开销,专心做垃圾回收工作,可以获得单线程环境下最高的收集效率
虽然上特点会让我们觉着会被舍弃这个收集器,但是目前依然是虚拟机在client默认的新生代垃圾收集器
Serial为什么要用作client端的新生代收集器?
原因:在用户的桌面应用中,一般分配给虚拟机的内存一般不会很大,收集几十兆甚至几百兆的内存,收集时间可以在几十毫秒或者几百毫秒之内,只要不频繁发生,这点停顿是可以接受的
ParNew收集器
是多线程版本的Serial,在Server中默认的新生代垃圾收集器。目前也只有它可以和CMS收集器配合工作。
CMS垃圾回收器是 唯一 一个可以并发的垃圾收集器。用户线程可以和垃圾回收线程同时工作,CMS作为老年代垃圾收集器
Parallel Scavenge收集器
新生代收集算法,使用复制算法的收集器
它和其他的收集器关注点不同,cms等收集器关注点在于尽可能短的缩短停顿的时间,而Parallel Scavenge收集器是达到一个可控制的吞吐量(吞吐量 = 执行用户代码的时间/(运行用户代码时间+垃圾收集时间)),高吞吐量可以高效的使用利用CPU时间,完成计算任务,一般使用于后台计算而不需要太多交互的任务。对于尽可能减少停顿时间的收集器来说,更适合用做用户交互的任务,有很好的交互体验。
由于与吞吐量关系密切,ParallelScavenge收集器也经常称为“吞吐量优先”收集器。除上述两个参数之外,Parallel Scavenge收集器还有一个参数-XX:+UseAdaptiveSizePolicy值得关注。这是一个开关参数,当这个参数打开之后,就不需要手工指定新生代的大小(-Xmn)、Eden 与Survivor区的比例(-XX:SurvivorRatio)、 晋升老年代对象年龄(XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC Ergonomics)。对于收集器运作原来不太了解,手工优化存在困难的时候,使用ParallelScavenge收集器配合自适应调节策略,把内存管理的调优任务交给虚拟机去完成将是一个不错的选择。只需要把基本的内存数据设置好(如-Xmx设置最大堆),然后使用MaxGCPauseMillis参数( 更关注最大停顿时间)或GCTimeRatio(更关注吞吐量)参数给虚拟机设立一个优化目标,那具体细节参数的调节工作就由虚拟机完成了。
自适应调节策略也是ParallelScavenge收集器与ParNew收集器的一个重要区别。
Serial Old收集器
Serial Old是Serial老年代版本,也同样是单线程收集器,使用”标记—整理”算法。这个收集器的主要意思在于在client下使用。如果使用在Server中,主要有两种用途。一中是在JDK1.5之前和ParallelScavenge搭配使用,另一种是作为cms的后备预案。
Parallel Old 收集器
Parallel Old是ParallelScavenge收集器老年代的版本,使用多线程和”标记—整理”算法。
cms收集器
老年代垃圾收集器,采用的是”标记—清除”算法,也被成为”并发低停顿收集器”
CMS (Concurrent Mark Sweep)收集器是一种以获取最矩回收停顿时间为8标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用护带来较好的体验。CMS收集器就非常符合这类应用的需求。
从名字(包含“Mark Sweep”)上就可以看出,CMS收集器是基于“标记-清除”算法实现的,它的运作过程相对于前面几种收集器来说更复杂- - 些,整个过程分为4个步骤,包括:
- 初始标记(EMS initial mark)
- 并发标记(CMS concurrent mark )
- 重新标记(CMS remark )
- 并发清除(CMS concurrent sweep )
其中,初始标记、重新标记这两个步骤仍然简要“Stop The World”.初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行Gc RootsTracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
G1收集器
是一款面向服务端的一款垃圾收集器
G1的优点:
并行与并发: G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU (CPU 或者CPU核心)来缩短Stop-The-WorId停顿的时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行
分代收集:与其他收集器一样,分代概念在G1中依然得以保留。虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同的方式去处理新创建的对象和已经存活了一段时间、熬过多次GC的旧对象以获取更好的收集效果。
空间整合:与CMS的“标记一清理”算法不同,G1从整体来看是基于“标记一整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。
可预测的停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java (RTSJ)的垃圾收集器的特征了。
在G1之前的收集器都是将JAVA堆区域分成新生代和老年代,但是G1虽然保留这两个概念,但是G1是把Java堆划分为多个大小相等的独立区域。它们不再是物理的隔离,它们都是一部分Region(不需要连续)的集合!
G1中的Region之间的对象引用以及其他收集器中的新生代和老年代的对象间对象引用,在做可达性分析对象是否存活时,需要判断,岂不是要扫描整个Java堆才可以保证准确性。但是,sun公司带来的解决方案是:虚拟机使用Remembered Set来避免全堆扫描的。虚拟机中每一个Region中都有一个Remembered Set,虚拟机发现程序在对Reference类型的数据进行写操作的时候,会产生一个Write Barrier暂停中断操作,检查Reference引用的对象是否存在同一个Region,如果是,便通过CardTable把相关引用信息记录到引用对象所在的Region对应的Rememberd Set之中。当进行垃圾回收时,在GC根节点的枚举范围中加入Rememberd Set 即可保证不对全栈扫描依然不会有遗漏!
总结
通过学习垃圾收集器的具体实现,然后结合之前的垃圾收集的四大方向,理清了JVM虚拟机HotSpot的垃圾收集机制!
收益颇多!继续学习。。。