美文网首页
垃圾回收

垃圾回收

作者: laowangv2 | 来源:发表于2021-01-31 14:45 被阅读0次

发现垃圾

1. 回收的区域

Java内存区域包括堆、虚拟机栈、本地方法栈、方法区、直接内存、程序计数器等。
其中需要回收的区域包括堆和方法区。

2. 判定垃圾的依据

  • 引用计数算法
    计数器,有一个引用就+1。问题是难以处理循环引用的问题。
  • 可达性分析算法
    从根出发,不能被触达的对象都会被当作垃圾回收。这里的根即GC Roots
    常见的GC Roots包括:
    • 虚拟机栈(栈帧中的本地变量表)中引用的东西。
    • 方法区中类静态属性引用的对象。
    • 方法区中常量引用的对象。
    • 本地方法栈中JNI(即一般说的Native方法)引用的对象。

3. 扩展知识

  • 引用类型
    强引用、软引用(内存满回收)、弱引用(一gc就回收)、虚引用(和没有一样,只是为了gc时先放入引用队列,消费这个队列就可以得知虚引用的对象被回收了,典型例子时堆外内存回收)
  • finalize

回收算法

  • 标记清除
    效率不高,有内存碎片
  • 复制
    相较于标记清除,效率会高些。但内存利用率不高
  • 标记整理
    如果对象存活率较高,复制算法的效率就会比较低。而且存在空间浪费。

回收策略

  • 分代收集
    三种回收算法有自己的特点,所以实践中选择将内存按照对象的存货周期划分为不同的区域,为不同的区域选择不同的回收算法。
  • 新生代
    • 新生代的对象大多“朝生夕死”,所以采用复制算法会比较合适。
    • 新生代被划分成1个Eden + 2个Survivor,大小为8:1:1。
    • 扩展1:为什么需要两个Survivor?
  • 老年代
    老年代对象存活率高,使用标记清除或者标记整理会更合适。

回收器

  • Hotspot
    HotSpot是Oracle JDK和OpenJDK所使用的虚拟机,本文的讨论基于使用HotSpot虚拟机的前提下。
  • 关键技术
    • 三色标记
      黑色集合:自身被访问,且引用也全部被访问过;灰色集合:自身被访问,引用还没被访问;白色集合:未被访问过。灰色集合全部放入黑色集合对应标记结束,结束后,白色集合被回收。
    • Card Table 和 Remember Set
      解决跨代引用的问题,卡表把被引用的card标记为脏,RSet记录哪些card引用了我的对象
    • 写屏障
      类似AOP,赋值操作时做一些额外操作
    • 增量更新和SATB
      三色标记法会有漏标的问题,并发标记阶段,一个灰对象的白对象引用赋值给黑对象,那么这个白对象就会被错误的回收掉。这种情况发生需要满足两个条件:一、灰色对象断开了白色对象的引用;二、黑色对象重新引用了该白色对象。那么只要破坏这两个条件就可以解决这种错误情况,分别对应的是增量更新(CMS)和SATB(G1),增量更新是记下条件二,重新标记的时候再扫一次;SATB则是记下条件一,重扫这个白色对象,效率更高,但可能丧失精度,让白色对象躲过GC。
    • 着色指针和读屏障
      G1的YGC和MixedGC都是STW的,因为其复制阶段不能解决并发访问的问题,着色指针可以告诉线程对象被移动了,那么访问时可以通过读屏障把最新地址读出来。
  • Serial
    单线程,Young GC和Old GC都会STW。YGC使用复制,OGC使用标记整理。
  • ParNew
    Serial的多线程版本
  • CMS
    目标是尽可能短的STW,用在老年代。我理解他就是拆分了可以和用户线程并发执行的过程出来,降低STW的时间。主要问题是CPU和内存碎片(因为用的标记清除)
    • background
      • 触发条件:后台线程2S判断一次是否满足以下条件
        1. 如果没有设置-XX:+UseCMSInitiatingOccupancyOnly,虚拟机会根据收集的数据决定是否触发(建议线上环境带上这个参数,不然会加大问题排查的难度),也就是2的配置会失效
        2. 老年代使用率达到阈值 CMSInitiatingOccupancyFraction,默认92%
        3. 永久代的使用率达到阈值 CMSInitiatingPermOccupancyFraction,默认92%,前提是开启 CMSClassUnloadingEnabled
        4. 判断当前新生代的对象是否能够全部顺利的晋升到老年代,如果不能,就提早触发一次老年代的收集
      • 流程:
        1. 初始标记
          STW,标记直接被GC Roots引用的对象和新生代中存活对象引用的老年代对象
        2. 并发标记
          顺着初始标记的对象继续标记,这一阶段引用关系会变,所以会把变了的对象的Card标记为Dirty
        3. 预清理
          重新标记Dirty Card中的对象
        4. 可终止的预处理
          这个阶段是为了减少重新标记STW的时间,做的事情和预清理一样。不过这里是循环的,直到一些条件被满足,比如超过5s、超过多少次之类。这一阶段如果期间发生了一次YGC,那么重新标记的时间又可以减少一些,也可以配置CMSScavengeBeforeRemark来强制触发一次YGC
        5. 重新标记
          STW,重新扫描整个堆,根据dirty card修正并发阶段引用关系的变化
        6. 并发清理
        7. 并发重置
    • foreground
      • 触发条件:
        1. Concurent Mode Failure,并发回收的同时,浮动垃圾导致老年代空间耗尽,只好STW,触发前台回收
        2. Promotion Failed,发生在Minor GC时,新生代提升失败,也只能触发STW来回收。
      • 算法:
        1. CMS自己的mark-sweep算法,串行不压缩,回收范围只有老年代
        2. 根据UseCMSCompactAtFullCollection和CMSFullGCsBeforeCompaction这两个参数来判断是不是选择带压缩的算法,如果是的话(默认是)就会使用Serial Old做整个堆的回收,也即Full GC
  • G1
    G1将整个内存分为多个region,这些region被标记为Eden,Survior或是Old。G1在回收时将存活对象从region移动到新的region,从全局看,使用的是标记整理。
    • 停顿预测模型
      基于历史数据(部分),衰减标准偏差(越老的影响越小)做预测
    • Young GC
      STW,将Eden中存活的对象复制到survivor或是old,和其他收集器差别不大。不过这里可以动态调整Eden和Survivor的大小以控制停顿时间
    • Marking Cycle
      我理解这一阶段是为了统计老年代的使用情况,方便收集的时候挑选垃圾最多的region。当堆使用率达到InitiatingHeapOccupancyPercent时触发,共分为五个阶段:
      1. Initial Mark,需要STW,所以会在YGC的同时进行这一阶段。标记可能含有指向old区引用的survivor region
      2. Root Region Scanning,扫描标记的survivor region。这一阶段完成前不能开始YGC
      3. Concurrent Marking,标记整个堆中的存活对象,这一阶段可以被YGC打断
      4. Remark,STW,使用SATB算法重新标记
      5. 清理,STW地去统计存活对象和完全空白的region、清理RSet。并行地去回收空白region
    • Mixed GC
      回收所有Young Region以及部分Old Region。Old Region在Marking Cycle阶段已经统计出了各自回收价值。
    • Allocation (Evacuation) Failure
      CMS所面临的Full GC风险在G1中同样存在,并且也是通过Serial的方式进行回收
    • Humongous Objects and Humongous Allocations
      超过region大小一般的对象会被放到特殊的连续的region,region放不满的空间会形成碎片。humongous region会在Collect Cycle的清理阶段和Full GC时回收

gc调优

参考

Java 垃圾回收权威指北
图解CMS垃圾回收机制,你值得拥有
CMS垃圾收集器
G1 垃圾收集器介绍

相关文章

  • 简单理解垃圾回收

    什么是垃圾回收? 垃圾回收的是什么? 如何判断为垃圾? 垃圾是怎样被回收的? 垃圾回收哪些区域的内存? 什么是垃圾...

  • JVM(二) GC算法与分代回收策略

    可达性分析 GCRoot场景 垃圾回收算法 分代回收策略 引用 垃圾回收 垃圾回收(Garbage Collect...

  • JVM调优之垃圾定位、垃圾回收算法、垃圾处理器对比

    谈垃圾回收器之前,要先讲讲垃圾回收算法,以及JVM对垃圾的认定策略,JVM垃圾回收器是垃圾回收算法的具体实现,了解...

  • 01垃圾回收机制

    垃圾回收(Garbage Collection,GC) 垃圾回收就是释放垃圾占用的空间 内存的动态分配和垃圾回收,...

  • Java 垃圾收集(GC)浅谈

    Java 垃圾收集(GC)浅谈 为什么需要垃圾回收?哪些内存需要回收?什么时候回收?如何回收? 为什么需要垃圾回收...

  • JVM垃圾回收机制

    JVM垃圾回收 整体思维导图 带着问题理解JVM垃圾回收机制 Java为什么需要垃圾回收机制; 回收哪部分垃圾; ...

  • 垃圾回收

    如何查看当前JVM使用的垃圾回收器? 如何指定使用CMS回收? 如何打印回收日志? 垃圾回收过程 CMS垃圾回收的...

  • JVM常见垃圾回收器介绍

    垃圾回收器简介 在新生代和老年代进行垃圾回收的时候,都是要用垃圾回收器进行回收的,不同的区域用不同的垃圾回收器。分...

  • JavaScript的垃圾回收机制

    大纲 1、认识垃圾回收机制2、垃圾回收机制的原理3、垃圾回收机制的标记策略4、垃圾回收机制与内存管理 1、认识垃圾...

  • 一文带你深入了解JVM性能调优以及对JVM调优的全面总结

    目录 JVM调优 概念 基本垃圾回收算法 垃圾回收面临的问题 分代垃圾回收详述1 分代垃圾回收详述2 典型配置举例...

网友评论

      本文标题:垃圾回收

      本文链接:https://www.haomeiwen.com/subject/rhizaktx.html