• JVM内存和垃圾回收-14.垃圾回收相关概念


    1.System.gc()的理解

    • 默认情况下,调用System.gc()Runtime.getRuntime().gc()会显示触发Full GC(对新生代和老年代同时进行回收)
    • 该方法被调用后并不能确保对垃圾回收器的调用,只是提醒垃圾回收器执行GC

    2.内存溢出和内存泄漏

    • 内存溢出:没有空闲内存,并且垃圾回收器也无法提供更多内存

      • 导致内存溢出的原因:
        • JVM堆的内存设置不足
        • 代码中创建了大量对象,且因为存在引用所以一直未被垃圾回收器收集
      • 在OOM前通常会触发垃圾回收,但是如果对象过大直接超出堆的最大值,JVM会认为垃圾回收无法处理,直接抛出OOM
    • 内存泄漏:对象不会被使用,但是GC又不能回收这些对象,比如在类中声明了很多静态变量(随着类的消亡而消亡),这些对象的生命周期较长,无法在短期被回收,最终导致了OOM

      • 举例:
        • 单例模式:如果某个单例的对象对另一个对象存在引用的话,由于单例对象中存在静态属性,因为着该单例对象随着程序的结束才会被回收,所以即使另一个对象不被使用,因为存在单例对象的引用,也无法被回收
        • 数据库连接、网络连接(连接会产生许多对象)未进行手动地关闭(调用close方法),需要等到程序结束才会被回收

    在这里插入图片描述


    3.Stop The World

    • 指在GC时会产生程序的停顿(整个应用程序线程都会暂停)
    • STW是JVM在后台自动发起和自动完成的
    • 可达性分析中因为需要枚举GC Roots,也会产生STW(没停止程序则可能会产生新的根节点)
    • 所有的GC都会产生STW
    • 开发中不要使用System.gc(会导致STW)

    4.垃圾回收的并行和并发

    • 操作系统中的并行和并发:

      • 并发:在一个时间段中几个程序处于已启动和运行完毕间,且这些程序都运行在一个CPU上(即CPU把一个时间段划分为几个时间片段,并在这些片段间来回切换)

      在这里插入图片描述

      • 并行:系统有多个CPU,每个进程在一个CPU上运行,进程间不抢占资源,可同时进行

      在这里插入图片描述

      • 对比:
        • 并发指多个任务在同一个时间段内同时发生;并行指多个任务在同一个时间点上同时发生
        • 并发多个任务会抢占资源;并行多个任务不会抢占资源
        • 并发发生在单CPU单核中;并行发生在多CPU或单CPU多核中
    • 垃圾回收的并行核并发:

      • 并行:指多条垃圾回收线程并行工作,但此时用户线程依旧处于等待状态;对应的另一个概念是串形(即单线程执行,如果内存不足则将当前程序暂停,启动JVM垃圾回收器进行GC,等回收完再启动程序)

      在这里插入图片描述

      • 并发:指用户线程和垃圾回收线程同时进行(即垃圾回收线程不会暂停用户线程),当然还是可能为交替执行的

      在这里插入图片描述


    5.安全点和安全区域

    • 安全点:程序执行时并不是在任意位置都可以停下来进行GC,只有在特定位置可以,这些位置称为安全点

      • 安全点少则导致GC等待时间长;安全点太多则导致运行时的性能问题(意味着需要不断切换)

      • GC时如果保证所有线程在最近的安全点停顿下来了?

        • 抢先式中断:如果还有线程不在安全点,就恢复线程,让线程执行到安全点
        • 主动式中断:设置一个中断标志,每个线程运行到安全点就轮询该标志(中断标志为真时线程就将自己挂起)
    • 安全区域:在一段代码中,对象的引用关系不发生变化,在这个区域任意位置进行GC都是安全的


    6.引用

    如果希望描述某些对象(比如缓存):当内存空间足够时,可以将这些对象保留在内存中;如果空间在GC后还是不足,则将这些对象进行抛弃(之前的描述中是考虑没有引用就选择抛弃,不管内存是否足够)

    注意:下面处理方式都是针对对象可达情况下的处理方式,对于不可达的即使是强引用也会被回收

    6.1 强引用-不回收

    • 最常见的普通对象引用(即A a = new A()),也是默认的引用类型
    • 只要强引用(可达)还存在,JVM宁愿抛出OOM,垃圾回收器永远不会回收被引用的对象(当然如果没被引用或将引用赋值为null,对象还是要被回收的)
    • 该引用是内存泄漏的主要原因之一

    6.2 软引用-内存不足即回收

    • 如果将不可达的对象进行回收后依旧内存不足,则会将软引用的对象(依旧可达)进行GC(回收完后还是内存不足就报OOM)
    • 该引用不是内存泄漏的原因(内存不足时该引用的都被回收了,再造成OOM就不是软引用的问题了)
    • 对于内存敏感的缓存会使用该引用,如高速缓存(有空闲空间就保留缓存;不足时会及时清理)

    6.3 弱引用-发现即回收

    • 只被弱引用关联的对象(依旧可达)只能生存到下一次GC前。GC时即使内存足够也会被回收(即使还存在弱引用导致对象还是可达的)
    • 与软引用的区别:软引用在GC回收时还要判断内存是否足够;弱引用内存足够也回收,回收更快

    6.4 虚引用-对象回收跟踪

    • 无论虚引用是否存在都不会对对象的生命周期造成影响(相当于对象不存在该引用)
    • 无法通过该引用获得对象实例,为对象设置该引用的主要目的是在该对象被GC时可以受到系统通知
    • 该引用必须和引用队列联合使用

  • 相关阅读:
    深入linux内核架构--内存管理
    rabbitMq 针对于当前监听的队列,来控制消费者并发数量,不影响其他队列,代码示例
    SpringCloud(三)Sentinel、Seata、多级缓存
    阿里云网络、数据中心和服务器技术创新优势说明
    【从零开始学习 SystemVerilog】7.1、SystemVerilog 类—— Class 概述
    vue中父子组件之间的访问方式-$children-$refs-$parent
    华东师范大学副校长周傲英:数据赋能,从数据库到数据中台
    企业级git工作流程
    死锁问题【javaEE初阶】
    vscode 提升Vue开发效率的必备插件与工具
  • 原文地址:https://blog.csdn.net/qq_41398418/article/details/126377759