学习笔记6——垃圾回收

学习笔记系列开头惯例发布一些寻亲消息

链接:https://baobeihuijia.com/bbhj/contents/3/190801.html
在这里插入图片描述

java垃圾回收(stop the world)

  • 专注于堆和方法区的垃圾回收,年轻代,老年代,永久代
  • 判断对象是否还存活?(区分尸体)
    • 引用计数算法
      • 给每个对象保存一个整型的引用计数器类型,用于记录对象被引用的情况
      • 缺点就是无法处理循环引用的情况,导致内存泄漏
    • 可达性分析算法
      • 找到GC ROOT对象,从根节点开始扩展访问
  • finalization机制(死前挣扎机制)
    • 用于在对象被回收时进行资源释放,比如关闭文件,套接字和数据库连接等。
    • 由于finalize的存在,对象有三种状态
      • 可触及的:活着
      • 可复活的:finalize重写过并且还没有执行,因此有机会进行死亡逃脱
      • 不可触及的:直接打死

在这里插入图片描述

  • 垃圾回收(三种算法清理尸体)

    • 复制算法(常用在新生代这种回收率较高的块上):有一块是专门用来备用的,清除的时候将存活对象复制到备用上,然后清除当前使用的内存块,交换两个的块的角色
    • 标记-清除算法:挨个清理,容易产生内存碎片,维护一个空闲列表,是一种非移动式的回收算法
    • 标记-压缩清除:在标记清除的基础上加上了内存碎片的整理,而不是维护一个列表,因此是一种移动式的回收算法
  • 增量收集算法:(解决stop the world)

    每次垃圾收集线程只收集一小片区域的内存空间,接着切换到应用程序线程。依次反复,直到垃圾收集完成。使用这种方式,由于在垃圾回收过程中,间断性地还执行了应用程序代码,所以能减少系统的停顿时间。但是,因为线程切换和上下文转换的消耗,会使得垃圾回收的总体成本上升,造成系统吞吐量的下降。

  • 分代算法和分区算法:针对不同情况用不同的垃圾回收算法

在这里插入图片描述

  • 内存溢出OOM和内存泄漏ML

  • stop the world,所有的GC都会有这种情况

  • GC的并发和并行

    • concurrent

      • 并发:多个事情在同一段时间内同时发生:用户线程和垃圾回收线程同时执行,不会停顿用户进程
    • STW

      • 并行:多个事情在用一个时间点上同时发生:多条垃圾回收并行,用户处于等待状态
      • 串行:相对于并行,单线程运行
  • 安全点: 数量需要适中,安全点实质上是一条指令(一般选择执行时间较长的指令作为安全点)

    • 抢先式中断:控制权在安全点,把所有线程挂起,没有运行到安全点的就恢复让运行到安全点
    • 主动式中断:线程运行到这里主动询问,主动挂起
  • 安全区:是扩展的安全点,在区域的任何位置GC都是安全的,安全区的对象引用关系不会变化

    • JVM会忽略标记进入到安全区的线程,线程还可以自主运行没有被停(因为其中的每句都是安全的)
    • 但等到线程出来的时候,就检查GC是否完成,完成了就可以走,没完成就得等着(要是进入了不安全区域,而且这个线程还没有被停住,就容易让JVM和改变后的引用关系发生冲突)
  • 引用(是有引用的可触及的对象,所以不会被判定为尸体,但是不一定有引用就会存活,也分情况)

    • 强引用(有用)

      • 只要引用关系存在,JVM宁愿OOM也不会回收对象
      • 是造成内存泄漏的原因之一
      • 强引用可以直接访问目标对象
    • 软引用(有用但是非必须)

      • 即将内存溢出时,回收这些软可达对象,回收后内存还是不够才抛出异常
    • weak弱引用(非必须)

      • 不管堆空间使用情况,下一次垃圾回收器工作一定会回收掉
      • GC的优先级很低,一般很久才能拿到线程,所以也能保有很久
      • 当系统内存不足时,这些缓存数据会被回收,不会导致内存溢出。而当内存资源充足时,这些缓存数据又可以存在相当长的时间,从而起到加速系统的作用。软引用、弱引用都非常适合来保存那些可有可无的缓存数据。
    • 虚引用:虚引用不会对对象的生存造成影响(如果只有虚引用,那么和没有引用是一样的)

      • 唯一作用就是对象回收时会收到一个系统通知,可以用来跟踪对象回收时间
    • 终结器引用(并不是一种对象还被别的对象需要的信号,而是将所有需要执行finalize的对象全都加进来

      • Finalizer线程通过终结器引用找到对象,并执行finalize方法
  • 垃圾回收器

    • 评价指标:吞吐量、暂停时间、占用内存

      • 个人理解:吞吐量是指用户的实际有效运行时间占比,暂停时间是用户需要等待GC的时间,这两者是相互冲突的。因为想要有效占比时间长,那么就需要GC不要那么频繁的发起回收,而是一次性高效回收完,回收时间较长,而暂停时间短,就需要每次GC的时间很短,但是发起次数比较频繁,导致程序吞吐量下降。
    • 不同垃圾回收器(年轻代和老年代的垃圾回收器进行组合)

      • 新生代:
        • serial:复制算法、串行回收、stop the world
        • ParNew:复制算法、并行回收、stop the world
        • parallel scavenge:复制算法、并行回收、stop the world、可控吞吐量(适用于不需要太多交互的场景)

      在这里插入图片描述

    在这里插入图片描述

    • 老年代

      • serial old:标记-压缩算法、串行回收、stop the world
      • parallel old:标记-压缩算法,并行,stop the world
      • CMS: 标记-清除算法、并发、stop the world,必须采用空闲列表而不是指针碰撞(与parallel scavenge不符,只能换别的新生代回收器)由于CMS回收过程中,应该确保应用程序也有部分的内存,所以CMS不能等到老年代全部满了再进行收集,到一定阈值就应该收集。当预留内存不满足应用程序要求的时候,就会出现concurrent failure,虚拟机会临时启动serial old回收,停顿时间变长。
        • 初始标记STW:GC Root
        • 并发标记Concurrent:遍历对象图
        • 重新标记STW:修正并发标记期间的错误
        • 并发清除Concurrent:清除标记阶段死亡的对象,释放内存空间

      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
      在这里插入图片描述

    • G1回收器:全能垃圾回收器

      • 将堆内存分为不同的region,尽量避免对整个堆全区域进行垃圾回收。
      • 跟踪每个区域的垃圾回收价值,维护一个优先列表,根据每次允许的收集时间优先回收价值最大的region
      • 并行与并发兼容:部分GC并行进行,部分工作可以与应用程序并发交替执行

      在这里插入图片描述

    • 流程

      • 年轻代回收过程:G1独占式并行运行,首先收集年轻代eden和survivor的内存回收片段,从年轻代移动存活对象到survivor或老年区间(最频繁使用的)

        • Rset避免全堆扫描root
        • 更新Rset(有的被老年代引用了)
        • 复制:将存活片段复制到survivor,空间不够就直接到old
      • 老年代并发标记过程:堆内存使用达到阈值(隔几天进行一次)

        • 初始标记阶段STW:标记根节点直接可达对象,触发Young GC
        • 根区域扫描(检查survivor直接可达老年代对象并标记)
        • 并发标记:计算区域的对象活性(存活比例)
        • 再次标记:修正并发标记的结果
        • 独占清理STW:计算存活对象和GC回收比例进行排序
        • 并发清理阶段
      • 老年代的混合回收:每次只扫描一小部分老年代的region,然后老年代和年轻代一起回收,为了避免堆内存被耗尽

      • Full GC:会产生大的停顿,尽量避免

    • Remember set

      在这里插入图片描述

      在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值