码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 基础 | java - [强引用、软引用、弱引用、虚引用]


    INDEX

        • §1 Reference
        • §2 各引用级别

    §1 Reference

    在 JDK 中,引用和对象一样,已经被抽象成了类,如下图
    在这里插入图片描述

    §2 各引用级别

    强引用 FinalReference

    • 强引用是最常见的引用,但 FinalReference 是非 public 的,因此不能如其他引用一样显示声明
    • 对象赋值给一个引用型变量,此变量就是一个强引用
    • 只要对象持有任意强引用,即可免疫 GC
      但可能造成无用对象依然被强引用指向,所以是内存泄漏的主因
      通常,对象超出引用作用于或显式置空(= null)就认为可以作为垃圾回收(还要参考垃圾回收策略)

    强引用 Finalizer

    • Finalizer 是对 FinalReference 的实现,也是非 public 的

    • 实现有 protected void finalize() throws Throwable { } 方法的对象会被识别为 Finalizer 对象

    • Finalizer 对象由 JVM 自动调用 register() 方法,完成创建,并在创建时将自己关联引用队列

    • Finalizer 通过 finalize() 定义了对象销毁时的自定义动作

    • Finalizer 对象至少需要两轮 GC 才能被回收,这是为了使被忘记释放资源的对象,即使真被忘了,也不会肯定不被回收

      • 第一轮:通过 finalize() 将 Finalizer 对象的连接放到它的引用队列中,但因为 Finalizer 本身就是个强引用所以还没有被 GC
      • 第二轮:若 Finalizer 对象只持有 Finalizer 引用队列的强引用了,才会通过正常方式 GC

    软引用 SoftReference

    • 软引用可以通过下面方式声明 Reference ra = new SoftReference<>(new AAA());
    • 支持有软引用的对象在 JVM 内存充足时免疫 GC,但不充足时会被回收,如下例
    • 内存不足 的界定
      • 快要 OOM 前,JVM 触发 GC
      • 执行后若依然要 OOM,认定内存不足,触发二次 GC,此时软引用纳入回收范围(下图中,可见两次 Full GC)
      • 若执行后依然要 OOM,那就 OOM 了
    • 可用于内存敏感型缓存 Map> cache = new HashMap<>();
    public class SoftReferenceDemo {
        public AAA b = new AAA();
        private Reference<AAA> ra = new SoftReference<>(new AAA());
    
        public Reference<AAA> getRa() {
            return ra;
        }
    
        public static void main(String[] args) {
            SoftReferenceDemo demo = new SoftReferenceDemo();
            System.out.println("================================");
            System.out.println(demo.b);
            System.out.println(demo.getRa().get());
            System.out.println("================================");
            try {
                int[] boom = new int[30*1024*1024];
            }catch (Throwable e){
                System.out.println("********************************");
                System.out.println("boom !!!");
                System.out.println("********************************");
            }finally {
                System.out.println("================================");
                System.out.println(demo.b);
                System.out.println(demo.getRa().get());
                System.out.println("================================");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述
    弱引用 WeakReference

    • 弱引用可以通过下面方式声明 Reference ra = new WeakReference<>(new AAA());
    • 只要 GC 就会被回收
    • 可以用来解决内存泄漏 Map map = new HashMap<>(); 或 WeakHashMap
      这种方式可以省略从容器中移除不需要的 key 的操作,以保证容器中的数据尽量齐全还不会导致内存泄漏
      但注意 线程不安全,同时只能用于存储 相对无关紧要 的数据,否则一个 GC 就丢了
    public class WeakReferenceDemo {
        public AAA b = new AAA();
        private Reference<AAA> ra = new WeakReference<>(new AAA());
    
        public Reference<AAA> getRa() {
            return ra;
        }
    
        public static void main(String[] args) {
            WeakReferenceDemo demo = new WeakReferenceDemo();
            System.out.println("================================");
            System.out.println(demo.b);
            System.out.println(demo.getRa().get());
            System.out.println("================================");
    
            System.gc();
    
            System.out.println("================================");
            System.out.println(demo.b);
            System.out.println(demo.getRa().get());
            System.out.println("================================");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    WeakHashMap
    WeakHashMap 是个 弱引用 版的 HashMap,其内部的 WeakHashMap.Entry 中 key 的类型为 WeakReference
    这意味着,一旦 GC,只要 key 不被其他强引用指向(比如是在字符串,在常量池里),WeakHashMap 就地清空
    见下面源码片段,和测试示例

    	// 此 Entry 非彼 Entry
    	Entry<K,V>[] table;
        public WeakHashMap(int initialCapacity, float loadFactor) {
            // 省略
            table = newTable(capacity);
            // 省略
        }
        // 此 Entry 中的 key 是 弱引用,所以一旦 GC,只要 key 不被其他强引用指向, WeakHashMap 就地清空
        private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
            V value;
            final int hash;
            Entry<K,V> next;
    		// 构造,注意 key 才是弱引用
    		Entry(Object key, V value,
                  ReferenceQueue<Object> queue,
                  int hash, Entry<K,V> next) {
                super(key, queue);
                this.value = value;
                this.hash  = hash;
                this.next  = next;
            }
            //省略
         }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    简单的测试
    在这里插入图片描述

    虚引用 PhantomReference

    • 虚引用,也称幽灵引用,是特殊引用
      • 不能往往对象(虚引用的 get() 永远返回 null)
      • 不影响对象的声明周期(不影响对象的 GC 抗性)
      • 仅持有虚引用的对象等同于 无引用,随时可能被 GC
    • 必须结合 ReferenceQueue 一起使用
    • 用于跟踪对象被 GC 的状态,实现当对象 finalize 后触发做某些事的机制,以实现比 finalization 机制更灵活的回收操作
      对象终止(finalization)机制:GC 对象前会先调用对象的 finalize() 方法,此方法允许重写。通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件、套接字和数据库连接等

    ReferenceQueue + WeakReference
    默认的,如果 SoftReference、WeakReference、PhantomReference 的对象 在声明时指定了 引用队列,如下例,则被 GC 时会执行 finalize() 方法,对象销毁后,上述引用本身不在指向对象,但 对象会存入 引用队列

    public void test() throws InterruptedException {
        ReferenceQueue<AAA> rf = new ReferenceQueue<>();
        Reference<AAA> weak = new WeakReference<>(new AAA(),rf);
    
        System.out.println(weak.get());//base.learning.AAA@3cd1a2f1
        System.out.println(rf.poll());//null
    
        System.gc();
        TimeUnit.SECONDS.sleep(1);
    
        System.out.println(weak.get());//null
        System.out.println(rf.poll());//引用还在 java.lang.ref.WeakReference@2f0e140b
    //        System.out.println(rf.poll().get());//引用不指向对象了 jnull
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    ReferenceQueue + PhantomReference

    public void test() throws InterruptedException {
        ReferenceQueue<AAA> rf = new ReferenceQueue<>();
        Reference<AAA> phantom = new PhantomReference<>(new AAA(),rf);
    
        System.out.println(phantom.get());
        System.out.println(rf.poll());
    
        System.gc();
        TimeUnit.SECONDS.sleep(1);
    
        System.out.println(phantom.get());
        System.out.println(rf.poll());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    四大引用对比
    四大引用的区别,主要集中在 对 GC 抵抗能力 上

    强软弱虚
    对应类ReferenceSoftReferenceWeakReferencePhantomReference
    是否常见√×××
    使用方式常规场景都是
    比如正常赋值
    但不能如其他引用直接声明
    Reference ra = new SoftReference<>(new AAA());类似 SoftReference配合引用队列
    new PhantomReference<>(new AAA(),rf);
    只持有此类引用的对象遇到垃圾回收时OOM 了都不收内存不足时回收只要 GC 就回收随时回收
    应用场景遍地都是内存敏感缓存(如 mybatis 中)解决容器不移除过期 key
    导致的内存泄漏
    WeakHashMap
    扩展 finalization 机制

    ReferenceQueue 与 finalize() 的区别

    • finalize() 是 JVM 回收对象之前自动调用,即在回收之前生效
    • ReferenceQueue 可以在对象被回收之后,额外保存其引用,即在回收之后生效

    本文部分内容摘自
    Java Reference详解
    JDK源码分析之FinalReference完全解读

  • 相关阅读:
    java计算机毕业设计西安市城市绿地管理系统源程序+mysql+系统+lw文档+远程调试
    论文解读(DAEGC)《Improved Deep Embedded Clustering with Local Structure Preservation》
    除静电离子风嘴的工作原理及应用
    【ArcGIS Pro微课1000例】0020:ArcGIS Pro中河流(曲线)、湖泊(水体色)图例制作案例教程
    NLP之多循环神经网络情感分析
    Spring系列-bean标签内autowire属性应用
    【Dart】002-函数
    vue按特定字符串切割后端传输的图片路径
    Spring Boot简介
    「干货」从动态的角度分析DDR的时序结构
  • 原文地址:https://blog.csdn.net/ZEUS00456/article/details/126562660
    • 最新文章
    • 攻防演习之三天拿下官网站群
      数据安全治理学习——前期安全规划和安全管理体系建设
      企业安全 | 企业内一次钓鱼演练准备过程
      内网渗透测试 | Kerberos协议及其部分攻击手法
      0day的产生 | 不懂代码的"代码审计"
      安装scrcpy-client模块av模块异常,环境问题解决方案
      leetcode hot100【LeetCode 279. 完全平方数】java实现
      OpenWrt下安装Mosquitto
      AnatoMask论文汇总
      【AI日记】24.11.01 LangChain、openai api和github copilot
    • 热门文章
    • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
      奉劝各位学弟学妹们,该打造你的技术影响力了!
      五年了,我在 CSDN 的两个一百万。
      Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
      面试官都震惊,你这网络基础可以啊!
      你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
      心情不好的时候,用 Python 画棵樱花树送给自己吧
      通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
      13 万字 C 语言从入门到精通保姆级教程2021 年版
      10行代码集2000张美女图,Python爬虫120例,再上征途
    Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
    正则表达式工具 cron表达式工具 密码生成工具

    京公网安备 11010502049817号