天天看点

二、对象判活算法、垃圾收集(GC)算法、垃圾收集器

此笔记出自《深入理解java虚拟机 第二版》,仅做摘要整理,详细了解可购买相关书籍。

图片扎堆,一是为了让文字更加紧凑,二是为了学习完文字知识后能单纯看图回顾,及时复习,三是增加不同类型之间对比。

三连问:哪些内存需要回收?什么时候回收?如何回收?

对象存活判定算法:2种

  • 引用计数算法:给对象添加应该引用计数器,引用到则+1,引用失效则-1,任何时刻计数器为0的对象就不可能再被使用。

    ​ 实现简单,效率高,但很难解决对象之间相互循环使用的例子。

  • 可达性分析算法:通过一系列的“GC Roots”的对象作为起始点,从这些节点往下搜索,走过的路径称为“引用链”,当一个对象到GC Roots没有任何引用链的时候,即不可达的时候,证明此对象不可用。
    • 如何挑选GC Roots:【PS:我个人理解:GC Roots它必须比较稳定,比较全局通用,在JVM里扎得比较深,所以不能是堆】
      • 虚拟机栈中引用的对象
      • 本地方法栈中引用的对象
      • 方法区中类静态属性引用的对象
      • 方法区中常量引用的对象
      • 由系统类加载器加载的对象(这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象。)
二、对象判活算法、垃圾收集(GC)算法、垃圾收集器

但是,真正宣告一个对象挂掉,至少要经历两次标记:

  • 可达性分析后,发现对象并没有和GC Roots相连接,那么,它将被第一次标记且进行第一次筛选:是否有必要执行finalize()方法?
    • 当对象没有覆盖finalize()方法或finalize()方法已被虚拟机调用过,那就判断为”没有必要执行“。那么这个对象算是可以静待死亡了。【PS:一个对象的finalize()方法最多被系统自动调用一次】
    • 如果判断”有必要执行“finalize()方法,对象将被放入一个F-Queue队列中,被Finalizer线程去执行,看看能否重新与引用链上的对象建立关联。
  • GC会对F-Queue队列进行第二次标记,在这期间,若对象重新链接上引用链,则存活,否则被回收。

垃圾收集(GC)算法:4种

  • 标记-清除算法:分为两个阶段:”标记“和”清除“
    • 标记:用上面提到的”判断对象是否存活“的算法标记所有需要回收的对象
    • 清除:在标记完成后统一回收被标记对象
    • 存在问题:
      • 1、效率问题:”标记“和”清除“两个阶段的效率都不算高
      • 2、空间问题:标记清除后会产生大量不连续的内存碎片,碎片过多会导致分配大对象时无法找到足够连续内存而触发了一次垃圾收集动作。
  • 复制算法:为了解决上面提到的效率问题,此算法诞生:将可用内存按容量划分为大小相等的两块,每次只用一块,A用完时将还存活的对象复制到另一块B上,将A全部清空。
    • 优点:回收:每次回收都是对整个半区的回收 分配:内存分配不需要考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配内存即可。
    • 缺点:显而易见,这个算法将内存缩小了一半,代价太高了。
    • 优化:新生代对象98%很快挂掉,1:1的操作代价太大,可用更合理些。比如:将内存分为一块较大(8)的”Eden空间“(伊甸园)和两块较小的(1:1)”Survivor空间“A和B,回收时,将Eden和SurvivorA中还存活的对象放入SurvivorB。这样的操作,内存的使用效率就高了起来。【Survivor空间不够放,爆炸了怎么办呢?不急,接着学。】
  • 标记-整理算法:复制算法在对象存活率较高的情况下要进行很多复制,效率变低,而且它没办法应付被使用内存中所有对象100%存活的极端情况,所以老年代一般不用这种算法。而标记-整理算法分为两个阶段:
    • 标记:和标记-清除算法应用
    • 整理:让所有存活对象向一端移动,直接清理掉端边界以外的内存。
  • 分代收集算法:根据对象存活周期的不同将内存分为几块,一般是将堆分为新生代和老年代。新生代采用复制算法,因为每次都有大批对象死去,少量对象存活;老年代对象存活率高,使用标记-清理算法或标记-整理算法。
二、对象判活算法、垃圾收集(GC)算法、垃圾收集器
二、对象判活算法、垃圾收集(GC)算法、垃圾收集器
二、对象判活算法、垃圾收集(GC)算法、垃圾收集器

垃圾收集器:7种

二、对象判活算法、垃圾收集(GC)算法、垃圾收集器
  • 新生代收集器
    • Serial收集器:**单线程;复制算法;**垃圾收集时,要暂停其他所有工作线程直到自己把活干完即收集结束—”Stop The World“
      • 优点:相比其他收集器的单线程而言,Serial简单高效;没有线程交互开销,在Client模式下的虚拟机来说是很好的选择
    • ParNew收集器:Serial收集器的多线程版本,除了多线程以外,其他完全一样
      • 优点:Server模式的虚拟机下首选的新生代收集器,因为除了Serial收集器外,只有它能和CMS收集器配合工作。
    • Paraller Scavenge收集器 [ˈskævɪndʒ] :多线程;复制算法;前面两个收集器力在尽可能减少收集时用户线程的停顿时间,而Paraller Scavenge收集器旨在达到一个可控制的吞吐量(”吞吐量优先“收集器)。【PS:吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间) 停顿时间越短,越适合需要用户交互的程序,因为可以提高用户体验;而吞吐量越高,越适合需要高效利用CPU时间尽快完成运算任务的程序,比如全是后台计算而不需要交互的程序。】
  • 老年代收集器
    • Serial Old收集器:Serial收集器的老年代版本;单线程;标记-整理算法
      • 用途:Client模式下的虚拟机使用;Server模式下的虚拟机使用时,一是与Parallerl Scavenge收集器搭配,二是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。
    • Parallel Old收集器:Parallel Scavenge收集器的老年代版本;多线程;标记-整理算法
      • 用途:以前Paraller Scavenge收集器只能用Serial Old收集器搭配,拖累了性能,吞吐量优先名存实亡。有了Parallel Old收集器以后,在注重吞吐量及CPU资源敏感场合,就可以优先考虑Parallel Scavenge和Parallel Old的搭配了。
    • CMS收集器:以获取最短停顿时间为目标的收集器,重视响应速度;并发收集、低停顿;标记-清除算法
      • 整个过程分4个步骤:
        • 1、初始标记:标记GC Roots能直接关联到的对象;Stop The World
        • 2、并发标记: 进行GC Roots Tracing的过程
        • 3、重新标记:修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录;Stop The World
        • 4、并发清除:清理线程后重置线程
        • 耗时最长的是两个并发是与用户线程一起工作的,四舍五入就是:CMS收集器的内存回收过程是与用户线程一起并发执行的。
      • 缺点:
        • “并发”的特点导致----对CPU资源非常敏感
        • “清理时用户线程也在工作”的特点导致----无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致一次Full GC,可以用Serial Old帮帮忙。【浮动垃圾:因为用户线程是一直在执行的,所以两次标记后产生的垃圾无法被收集处理,只能等下次GC时清理,就叫浮动垃圾。】
        • ”使用标记-清除算法“的特点导致—收集结束后会有大量的空间碎片产生,给大对象分配造成麻烦。

G1收集器:面向服务端;并行与并发;分代收集;标记-整理算法、复制算法;可预测的停顿

  • 并行与并发:利用多CPU的优势来缩短Stop The World的停顿时间,并发可让Java程序继续执行
  • 分代收集:仍保留分代概念,但不需要像其他收集器一样,搭配着来处理新生代和老年代,这哥们一个打俩,即采用不同的方式去处理新生代和老年代,可以独立管理整个GC堆。
  • 标记-整理算法、复制算法:整体来看,是标记-整理算法,局部来看是复制算法;总之就是不使用CMS用的标记-清理算法,这样就不会产生内存空间碎片,利于程序的长时间运行。
  • 可预测的停顿:建立可预测的停顿时间模型,明确在一个M毫秒的时间片段内,垃圾收集时间不得超过N毫秒。

    为了规避进行整个堆的垃圾收集,G1将堆划分为很多区域(region),优先回收价值最大(优先级大)的区域(Garbage-First)。这种用Region划分内存空间以及由优先级的区域回收方式,保证了G1收集器在有限时间内可以获取尽可能高的收集效率。

  • G1收集器的运作步骤:(对比一下CMS收集器)
    • 初始标记:标记GC Roots能直接关联到的对象,并修改TAMS(Next Top at Mark Start)的值,需要stop
    • 并发标记:进行GC Roots Tracing;时间较久,不用stop
    • 最终标记:修正并发标记期间产生变动的标记记录
    • 筛选回收:根据Region的回收价值和成本进行排序,然后回收;可与用户线程同时进行,但stop能大幅提高效率
二、对象判活算法、垃圾收集(GC)算法、垃圾收集器
二、对象判活算法、垃圾收集(GC)算法、垃圾收集器