jvm-分代垃圾收集器

212 阅读3分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

垃圾收集器

image.png

JDK1.8 默认的垃圾回收器 :Parallel Scavenge + Parallel Old ,所以调优主要针对的就是它。

image.png

useParallelGc

image.png

新生代垃圾收集器

新生代的垃圾回收器都是基于复制算法

  • 1.Serial:单线程的垃圾回收器,STW (stop-the-world)停止所有线程

    • 优点

    客户端模式下默认的新生代收集器,简单高效(相比于其他收集器的单线程)

    内存占用最小

    最高的单线程收集效率:没有线程交互的开销

  • 2.ParNew

    • Serial 的 多线程并行版本,在单线程情况下效率比不上Serial。

      处理器核心越多,它的效率越高,因为是并行。默认开启收集线程数 = 处理器核心数。

    • 和CMS 配合使用。

  • Parallel Scavenge

    • 和ParNew非常相似,但是关注点不同:达到一个可控制的吞吐量:运行用户代码时间/(运行用户代码时间+运行垃圾收集时间)这个值默认99,越高越好。
    • 和Parallel Old搭配使用

老年代垃圾收集器

老年代的垃圾收集器都是基于 标记压缩算法

  • 1.Serial Old

    Serial的老年代版本。

  • 2.Parallel Old

    Parallel Secavenge 的老年代版本,与Parallel Secavenge 搭配使用,组成吞吐量优先的搭配组合

  • 3.CMS

CMS

ConcurrentMarkSweep,以获取最短回收停顿时间为目标的收集器。基于标记清理算法(不是标记压缩)

用于服务端,关注服务器响应时间,希望系统停顿时间尽量少垃圾回收运行期间用户线程也能运行

四个步骤
  • 初始标记

    • 找到GC Roots能关联的类,这个阶段也会STW ,但是时间很短。
  • 并发标记

    • 并发的可达性分析,基于三色标记算法,这个最耗时

    • 垃圾回收线程和业务线程同时执行

    • 产生的并发问题

    1.当业务线程使用对象的时候垃圾线程也标记了这个对象,那么垃圾线程会认为这个线程存活对象,但是业务线程用完后就不再使用了,这个垃圾还是标记为存活对象

    2.垃圾线程标记对象为垃圾,但是这时业务线程又使用了这个对象。那么这个在使用的对象就会标记称垃圾。

  • 重新标记

    • 修正漏标和错标,这个阶段STW,但是时间也不长
  • 并发清除

    • 使用标记清除算法,将标记的对象直接删除,和用户线程并发执行。由于使用清除算法,会产生碎片
    • 为何不适用压缩算法? 如果使用压缩算法,会涉及到用户线程正在使用,情况更加复杂,用户线程不停顿很难处理
    • 可能会出现浮动垃圾:在清除阶段用户产生的新垃圾,但是CMS在本次垃圾回收中无法处理,只能等到下次CMS回收。
并发模式失败

CMS 无法处理浮动垃圾可能会"Concurrent Mode Failure”失败,导致Full GC

失败原因:

1.对象提升到老年代的速度很快,使得CMS 不能保持老年代足够的空间

2.大量碎片化导致没有足够的空间容纳提升上来的新对象。

年老代将进行垃圾收集以释放可用空间,同时也会整理压缩以消除碎片,这个操作需要停止所有的java应用线程,并且需要执行相当长时间。

  • 三色标记
  • 黑色:对象已经被收集器访问过,并且它的所有引用也已经访问过,代表它是线程安全的。
  • 灰色:表示对象已经被垃圾收集器访问过,但是至少存在一个引用还没有被扫描过
  • 白色:这个对象还没有被扫瞄过。