垃圾收集器

 在上一篇提到垃圾收集算法,那么在堆中怎么选择呢?

Young区:复制算法(对象在被分配之后,可能生命周期比较短,Young区复制效率比较高)

Old区:标记清除或标记整理(Old区对象存活时间比较长,没必要进行复制,直接做标记之后清理)

  • Serial收集器

  Serial搜集器是最基本的收集器。它是一种单线程的收集器,不仅仅以为着他指挥使用一个CPU或者一条收集线程去完成垃圾收集工作,更重要是其在进行垃圾回收的时候需要暂停其他线程。

  优点:简单高效,拥有很高的单线程手机效率

  缺点:手机过程需要暂停的所有线程

  算法:复制算法

  使用范围:新生代

  应用:client模式下的默认新生代收集器

  

 

  • ParNew收集器

  可以把这个收集器理解为Serial收集器的多线程版本

  优点:在多CPU的时候,比Serial效率高

  缺点:收集过程暂停所有应用程序线程,单CPU时比Serial效率差

  算法:复制算法

  使用范围:新生代

  应用:运行在server模式下的虚拟机中首选的新生代收集器

 

  • Parallel Scavenge收集器

  Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器,看上去和ParNew一样,但是Parallel Scanvenge更关注系统的吞吐量

  吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集时间)

  如果吞吐量越大,意味着垃圾收集的时间越短,则用户代码可以充分利用CPU的资源,尽快完成程序的运算任务。

-XX:MaxGCPauseMillis    控制最大的垃圾收集停顿时间
-XX:GCTimeRatio    直接设置吞吐量的大小
  •  Serial Old收集器

  Serial Old收集器是Serial收集器的老年代版本,也是一个单线程收集器,不同的是采用“标记-整理算法”,运行过程和Serial收集器一样。

  • Parallel Old收集器

  Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理算法”进行垃圾回收。吞吐量优先

  • CMS收集器

  CMS(concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。

采用的是“标记-清除算法”。

  其过程为:

    • 初始标记 CMS initial mark  标记GC Roots能关联到的对象 Stop The World--》速度很快
    • 并发标记 CMS concurrent mark 进行GC Roots Tracing
    • 重新标记 CMS remark。修改并发标记因用户程序变动的内容。Stop The World
    • 并发清除 CMS concurrent sweep

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

  优点:并发收集、低停顿

  缺点:产生大量的空间碎片、并发阶段会降低吞吐量

  • G1收集器

G1的特点:

    • 并行与并发  
    • 分代收集(仍然保留了分代的概念)
    • 空间整合(整体上属于“标记-整理“算法,不会导致空间碎片)
    • 可预测的停顿(比CMS更先进的地方在于能让使用者明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒)
    • G1收集器会先收集存活对象少的区域,也就是垃圾对象多的区域,这样可以有大量的空间释放出来,这就是Garbage First的由来

使用G1收集器时,Java堆的内存布局与就与其他收集器有很大的差别,它将整个java堆划分为多个大小相等的独立区间(region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分region(不需要连续)的集合。

工作过程可以分为如下几个步骤:

  • 初始标记(Initial Marking) 标记一下GC Roots能够关联的对象,并且修改TAMS的值,需要暂停用户线程。
  • 并发标记(concurrent Marking) 从GC Roots进行可达性分析,找出存活对象,与用户线程并发执行。
  • 最终标记(Final Marking) 修正在并发标记阶段因为用户程序的并发执行导致变动的数据,需要暂停用户线程
  • 筛选回收(Live Data Counting and Evacuation) 对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间制定回收计划

如图所示:

  • 垃圾收集器分类

    • 串行收集器-》Serial和Serial Old
      • 只能有一个垃圾回收线程执行,用户线程暂停。适用于内存较小的嵌入式设备
    • 并行收集器【吞吐量优先】-》Parallel Scanvenge、Parallel Old
      • 多余垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。适用于科学计算、后台处理等若交互场景。
    • 并发收集器【停顿时间优先】-》CMS、G1
      • 用户线程和垃圾收集线程同时执行(但不一定是并行的,可能是交替执行的),垃圾收集线程在执行的时候不会停顿用户线程的运行。适用于对时间有要求的场景。比如web
  • 吞吐量和停顿时间

    • 停顿时间-》垃圾收集器进行垃圾回收终端应用执行响应的时间
    • 吞吐量-〉运行用户代码时间/(运行用户代码时间+垃圾收集时间)

    【停顿时间越短就越适合和用户交互的程序,良好的响应速度能提升用户的体验;

     高吞吐量则可以高效的利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多的交互的任务。

     】

总结:吞吐量和停顿时间是评价垃圾回收器好处的标准,其实调优也就是在观察者两个变量。

如何选择选择合适的垃圾收集器

  • 优先调整堆的大小让服务器自己来选择
  • 如果内存大小小于100M,使用串行收集器
  • 如果是单核,并且没有停顿时间要求,使用串行或jvm自己选
  • 如果允许停顿时间超过1s,选择并行或jvm自己选
  • 如果响应时间最重要,并且不能超过1s,使用并发收集器

如何开启需要的垃圾收集器?

  • 串行

    • -XX: +UseSerialGC

    • -XX: +UseSerialOldGC

  • 并行(吞吐量优先)

    • -XX:+UseParallelGC

    • -XX:  +UseParallelOldGC

  • 并发收集器(响应时间优先)
    • -XX: +UseconcMarkSweepGC
    • -XX: +UseG1GC

 有关在不同垃圾收集器中使用的不同的算法的图解参考:https://www.cnblogs.com/LBJLAKERS/p/12287322.html

posted @ 2020-02-11 17:46  白天黑天阴天  阅读(181)  评论(0编辑  收藏  举报