2.垃圾回收GC

2垃圾回收GC

1.基础理论

1.1对象回收的条件

  • 引用计数算法
    • 为对象添加一个引用计数器,当有一个地方引用它时就加一,当一个引用失效时就减一。
    • 但没法解决循环引用问题:A引用B,B引用1。此时引用计数器永远不可为0。
  • 可达性分析算法
    • 从GC ROOTS开始寻找,当对象不存在于引用链中时,便为可回收对象。
    • JVM采用的就是这种方式。
    • GC ROOTS:
      • 虚拟机栈的本地变量表中引用的对象
      • 方法区中静态属性引用的对象
      • 方法区中常量引用的对象
      • 本地方法栈中JNI引用的对象
    • 引用的类型
      • 强引用:永远不会回收。
      • 软引用:内存够就不会回收。常用于缓存。
      • 弱引用:存活到下一次回收之前。
      • 虚引用:任何时候都可以被回收。回收时得到一个系统通知。

1.2垃圾回收算法

  • 标记清除
    • 先对所有应该被回收的对象进行标记,标记之后统一进行回收。
    • 完全标记与清除效率不高,且产生大量内存碎片,内存不连续不利于大对象的分配。
  • 复制
    • 将内存空间分为两部分,每次只是用一部分,当那部分的内存用完时将存活的复制到另一部分上,然后对整个部分进行回收。
    • 内存变为原来的一般,内存代价较高。对象存活率较高时需要复制的太多,效率变低。
    • 解决了内存不连续的问题。
  • 标记整理
    • 标记整理同标记清除类似,先对所有被回收的对象进行标记,之后将存活的对象向一端移动,并直接清理掉剩余的部分。
    • 解决了标记整理算法在内存存活率高时的效率问题,且内存效率为100%。
    • 常用于老年代。
  • 分代收集
    • 在JVM中一般将堆分为新生代和老年代,新生代中总有大量对象死去因此采用复制算法,而老年代对象存活率高一般采用标记清除和标记整理。

1.3安全点安全区

  • 在进行GC的标记时需要暂停所有线程的工作以防止引用发生变化,因此必须设置安全点/区来防止问题的发生。
  • OopMap
    • 存储的是GC ROOTS,回收时无需为了寻找GC ROOTS扫描所有位置。
    • 类加载和编译时就到堆中的引用添加到OopMap中。
  • 安全点
    • 并非为每一条导致OopMap改变的指令都添加OopMap操作指令。
    • 因此这些添加了OopMap的位置就是安全点。
    • 抢先式中断
      • 将所有线程停止,并让不在安全点的线程执行到安全点再停止。
    • 主动式中断
      • 设置一个中断标志,线程轮询此标志,当所有线程都停止时进行GC标记。
      • 一般采用此种方式。
  • 安全区
    • 若有线程当前不处于运行状态时,若此线程暂停在非安全位置,则可能导致问题。
    • 因此只有它在没有进行引用关系变化的安全区内时才可以,并在离开安全区时检测GC标记是否结束。

2.JVM中的垃圾回收

2.1回收区域

    • 新生代(Eden、Survivor),老年代
  • 方法区
    • 废弃常量,无用的类(并不是一定有回收功能)
    • 废弃常量
      • 该类的所有实例已被回收
      • 该类的ClassLoader已经被回收
      • 该类对应的Class对象不被引用,且无法在任何地方通过反射访问该类。

2.2内存分配与回收策略

  • 内存分配
    • 指针碰撞
      • 堆是规整的,指针指向保存对象的最后地址
    • 空闲列表方式
      • 堆可以是不规整的,列表保存所有的对象。
    • 选择方式
      • 堆是否规整-垃圾收集器是否含有压缩整理功能决定。
        • Serial ParNew等带整理功能的垃圾收集器使用指针碰撞
        • CMS这种Mark-Sweep算法的使用空闲列表
  • 优先Eden区
    • 内存不够时进行minor GC
  • 大对象直接分配到老年区
  • 长期存活的放入老年区
    • 在eden的对象在第一次Minor GC后分配到survivor区
    • 在survivor区的熬过15次Minor GC进入老年代

2.3垃圾回收器

  • 新生代

    • Serial 复制算法 单线程 非并发 可配合CMS Clinent默认
      ParNew 复制算法 多线程 非并发 可配合CMS Server默认
      Parallel Scanvenge 复制算法 多线程 非并发 不可配合CMS 可控吞吐量
  • 老年代

  • Serial Old 标记整理 单线程 非并发 可配合Parallel Scanvenge
    Parallel Old 标记整理 多线程 非并发 可配合Parallel Scanvenge
    CMS 标记清除 并发 不可配合Parallel Scanvenge
  • CMS

    • CMS垃圾收集步骤:

      • 1.初始标记 stop world 单线程/可调 非并行
        2.并发标记 未知 与用户进程同时并行
        3.重新标记 stop world 多线程 非并行
        4.并发清除 多线程 与用户进程同时并行
    • 初始标记

      • 标记一下GC Roots能直接关联到的对象,速度很快。
    • 并发标记

      • GC Roots Tracing
    • 重新标记

      • 修正并发标记期间,标记变动的对象的标记记录,停顿时间略长于初始标记
  • G1

    • 可以收集整个堆的垃圾
    • 分为内存多个region
发布了27 篇原创文章 · 获赞 1 · 访问量 902

猜你喜欢

转载自blog.csdn.net/hu853996234/article/details/103689726