g1和cms对比

Stop the world

不管选择哪种GC算法,stop-the-world都是不可避免的。Stop-the-world意味着从应用中停下来并进入到GC执行过程中去。一旦Stop-the-world发生,除了GC所需的线程外,其他线程都将停止工作,中断了的线程直到GC任务结束才继续它们的任务。GC调优通常就是为了改善stop-the-world的时间。

GC roots

在Java语言中,可作为GC Roots的对象包括4种情况:

  • 虚拟机栈中引用的对象(栈帧中的本地变量表)
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(Native方法)引用的对象

CMS收集器

MS收集器是一种以获取最短回收停顿时间为目标的收集器,CMS收集器是基于“”标记--清除”(Mark-Sweep)算法实现的,整个过程分为四个步骤:  

  1. 初始标记 (Stop the World事件 CPU停顿, 很短) 初始标记仅标记一下GC Roots能直接关联到的对象,速度很快;
  2. 并发标记 (收集垃圾跟用户线程一起执行) 初始标记和重新标记需要“stop the world”,并发标记过程就是进行GC Roots Tracing的过程;
  3. 重新标记 (Stop the World事件 CPU停顿,比初始标记稍微长,远比并发标记短)修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记时间短
  4. 并发清理 -清除算法

整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。 

优点:

并发收集,低停顿。由于在整个过程和中最耗时的并发标记和 并发清除过程收集器程序都可以和用户线程一起工作,所以总体来说,Cms收集器的内存回收过程是与用户线程一起并发执行的

缺点:

CMS收集器对CPU资源非常敏感 :在并发阶段,虽然不会导致用户线程停顿,但是会因为占用了一部分线程使应用程序变慢,总吞吐量会降低,为了解决这种情况,虚拟机提供了一种“增量式并发收集器” 的CMS收集器变种, 就是在并发标记和并发清除的时候让GC线程和用户线程交替运行,尽量减少GC 线程独占资源的时间,这样整个垃圾收集的过程会变长,但是对用户程序的影响会减少。(效果不明显,不推荐) 

 CMS处理器无法处理浮动垃圾:CMS在并发清理阶段线程还在运行, 伴随着程序的运行自然也会产生新的垃圾,这一部分垃圾产生在标记过程之后,CMS无法在当次过程中处理,所以只有等到下次gc时候再清理掉,这一部分垃圾就称作“浮动垃圾” , 

大量的空间碎片:CMS是基于“标记--清除”算法实现的,所以在收集结束的时候会有大量的空间碎片产生。空间碎片太多的时候,将会给大对象的分配带来很大的麻烦,往往会出现老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配当前对象的,只能提前触发 full gc。 

为了解决这个问题,CMS提供了一个开关参数,用于在CMS顶不住要进行full gc的时候开启内存碎片的合并整理过程,内存整理的过程是无法并发的,空间碎片没有了,但是停顿的时间变长了

G1

G1(Garbage First)是一款面向服务端应用的垃圾收集器,整个过程分为四个步骤:  

  1. 初始标记(stop the world事件 CPU停顿只处理垃圾);
  2. 并发标记(与用户线程并发执行);
  3. 最终标记(stop the world事件 ,CPU停顿处理垃圾);
  4. 筛选回收(stop the world事件 根据用户期望的GC停顿时间回收)

G1除了并发标记这一步,其他都要stop the world。

优点:

  • 并行于并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短stop-The-World停顿时间。部分其他收集器原本需要停顿线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。
  • 分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。它能够采用不同的方式去处理新创建的对象和已经存活了一段时间,熬过多次GC的旧对象以获取更好的收集效果。
  • 空间整合:与CMS的“标记--清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的
  • 可预测的停顿:这是G1相对于CMS的另一个大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内。
  • 在G1中,还有一种特殊的区域Humongous。 如果一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象。这些巨型对象,默认直接会被分配在年老代,但是如果它是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响。为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。
  • G1回收是选择一些内存块,而不是整代内存来回收。其它GC每次回收都会回收整个Generation的内存(Eden, Old), 而回收内存所需的时间就取决于内存的大小,以及实际垃圾的多少,所以垃圾回收时间是不可控的;而G1每次并不会回收整代内存,到底回收多少内存就看用户配置的暂停时间,配置的时间短就少回收点,配置的时间长就多回收点,伸缩自如。

缺点:

 如果应用的内存非常吃紧,对内存进行部分回收根本不够,始终要进行整个Heap的回收,那么G1要做的工作量就一点也不会比其它垃圾回收器少,而且因为本身算法复杂了一点,可能比其它回收器还要差。因此G1比较适合内存稍大一点的应用(一般来说至少4G以上),小内存的应用还是用传统的垃圾回收器比如CMS比较合适。

你可能感兴趣的:(jvm)