美文网首页
JVM垃圾回收

JVM垃圾回收

作者: 知而乐者 | 来源:发表于2020-03-21 15:47 被阅读0次

    什么需要回收

    如何判断对象是否已死?

    • 引用计数法
      记录被引用的次数,当为0时就可以回收,确定会有循环依赖的问题,但是高效
    • 可达性分析法
      通过GCRoot为根节点开始查找,能找到的为存活对象,否则为需要清理的对象
      GCRoot包括,虚拟机栈(局部变量表中引用的对象),方法区中类静态属性引用对象,方法区中常量引用对象,本地方法栈中引用对象(Native引用对象)

    其他说明

    • 方法区的回收判断条件比较苛刻
      该类所有对象都已经被回收
      类的加载器已经被回收
      类对应的Class对象没有任何地方被访问,没有被反射访问
    • 枚举根节点
      可达性分享中寻找GCRoot会特别难,比如只是扫描方法区可能就数百兆。所以需要记录枚举根节点。在HotSpot的实现使用OopMap数据结构来存储,每次类加载完成后放入OopMap中GC的时候就可以直接使用
    • 安全区
      为了解决每一条指令都放入OopMap中可能导致空间太大,所以引入安全区的概念,当GC发生时所有线程都执行到安全区然后标示自己已经进入safeRegion,当出去时要判断是否已经完成根节点的枚举(或整个GC过程)

    垃圾回收算法

    标记清除法

    • 分为标记和清除两步,先标记需要回收对象,然后进行清除
    • 问题:效率慢,会产生大量不连续的内存碎片

    复制算法

    • 将空间划分使用和未使用的,每次清理的时候将存活对象存入未使用区域,然后直接清除已使用的区域
    • 问题:存活率高时,会造成效率变低。会造成内存的浪费。(新生代使用的回收算法)

    标记整理法

    • 将存活的对象向一端移动,最后清除掉其他区域
    • 问题:效率慢

    分代收集算法

    • 将内存划分代,根据各个代的特点使用不同的回收算法,如:新生代使用复制算法,老年代使用标记清除

    垃圾回收器

    连线代表可以一块使用

    作用于新生代的垃圾回收器有:Serial,ParNew,Parallel Scavenge
    作用于老年代的垃圾回收器有:CMS,Serial Old, Parallel Old
    G1收集器即可以作用于新生代又可以作用域老年代

    • Serial收集器
      所有线程跑到安全区后暂停,开启单线程进行清理。清理完成后线程开始执行,采用复制算法
    • ParNew收集器
      Serial收集器多线程版本,清理是开启多线程
    • Parallel Scavenge收集器
      Parallel Scavenge收集器也是新生代收,复制算法、多线程收集器。于ParNew不同的是关注的是一个可控制的吞吐量,可以设置最大垃圾收集停顿时间以及直接设置吞吐量大小
    • Serial Old收集器
      老年代的收集器,采用标记整理的算法。主要在Client模式下的虚拟机使用
    • Parallel Old收集器
      是Parallel Scavenge老年代版本,采用标记整理的算法,只能和新生代的Parallel Scavenge收集器共同使用
    • CMS收集器


      image.png

    CMS是以获取最短停顿时间为目标的收集器,采用标记-清除的算法,分为4步:初始标记-》并发标记-》重新标记-》并发清除
    初始标记:标记GCRoot。很快,但需要STW
    并发标记:通过初始标记的GCRoot去追踪标记内存中的对象,和用户线程一块跑(耗时较长)
    重新标记:修正在在并发标记有变动的部分,停顿时间比初始标记长但远比并发标记短,需要STW
    并发清除:和用户线程一块进行清除垃圾数据
    问题:会有碎片,对CPU要求高只有一个CPU的话性能反而会低,产生浮动垃圾(就是清理的时候又产生了垃圾)

    • G1收集器


      image.png

    相关文章

      网友评论

          本文标题:JVM垃圾回收

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