登录 |  注册
首页 >  架构·案例 >  架构师学习之路-Java开发实战学习笔记 >  Java强软弱虚四种引用,看完不再犯迷糊

Java强软弱虚四种引用,看完不再犯迷糊

其实强引用、软引用、弱引用、虚引用这四个概念非常简单好记。

在开头先总结一下这四个引用的特点吧。

  • 强引用:gc时不会回收

  • 软引用:只有在内存不够用时,gc才会回收

  • 弱引用:只要gc就会回收

  • 虚引用:是否回收都找不到引用的对象,仅用于管理直接内存

接下来详细看看这四种引用,结合代码,深刻的体会一下。

强引用

即我们平时最常见的:

Object object = new Object();

ref.png

只要一个对象有强引用,垃圾回收器就不会进行回收。即便内存不够了,抛出OutOfMemoryError异常也不会回收。

上demo,注意注释

/**
 * 一个对象
 * 重写finalize方法,可以知道已经被回收的状态
 *
 * @author 
 * @date 2020-05-23
 */
public class OneObject {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("啊哦~OneObject被回收了");
    }
}
/**
 * 强引用例子
 *
 * @author 
 * @date 2020-05-23
 */
public class ShowStrongReference {
    public static void main(String[] args) {
        // 直接new一个对象,就是强引用
        OneObject oneObject = new OneObject();
        System.out.println("输出对象地址:" + oneObject);
        System.gc();
        System.out.println("第一次gc后输出对象地址:" + oneObject);
        oneObject = null;
        System.gc();
        System.out.println("置为null后gc输出对象地址:" + oneObject);
    }
}

执行代码,可以看到以下输出:

输出对象地址:com.esparks.pandora.learning.references.OneObject@72ea2f77
第一次gc后输出对象地址:com.esparks.pandora.learning.references.OneObject@72ea2f77
置为null后gc输出对象地址:null
啊哦~OneObject被回收了

软引用

需要通过SoftReference对象实现:

SoftReference<OneObject> oneObjectSr = new SoftReference<>(new OneObject());

软引用.png

当内存足够的时候,垃圾回收器不会进行回收。当内存不够时,就会回收只存在软引用的对象释放内存。

常用于本地缓存处理。

上demo,注意注释

/**
 * 软引用
 * 内存不够了就会回收
 * 注意,运行时需要保证heap大小为35m,即小于实验中全部对象的大小,才能触发gc
 * -Xmx35m
 *
 * @author 
 * @date 2020-05-23
 */
public class ShowSoftReference {
    public static void main(String[] args) {
        // 我们需要通过SoftReference来创建软引用
        SoftReference<OneObject> oneObjectSr = new SoftReference<>(new OneObject());
        // 我们这里创建一个大小为20m的数组
        SoftReference<byte[]> arraySr = new SoftReference<>(new byte[1024 * 1024 * 20]);
        System.out.println("软引用对象oneObjectSr的地址:" + oneObjectSr);
        System.out.println("通过oneObjectSr关联的oneObject对象的地址:" + oneObjectSr.get());
        System.out.println("数组的地址:" + arraySr.get());
        System.gc();
        System.out.println("正常gc一次之后,oneObject对象并没有回收。地址" + oneObjectSr.get());
        // 再创建另一个大小为20m的数组,这样heap就不够大了,从而系统自动gc。如果依旧不够,会把已有的软引用关联的对象都回收掉。
        System.out.println("创建另一个大小为20m的数组otherArray");
        byte[] otherArray = new byte[1024 * 1024 * 20];
        System.out.println("otherArray的地址:" + otherArray);
        // gc后,软引用对象还在,但是通过软引用对象创建的对象就被回收了
        System.out.println("现在srObject的地址:" + arraySr);
        System.out.println("现在srObject中oneObject对象的地址:" + arraySr.get());
        System.out.println("刚才的数组对象也被回收啦,地址:" + arraySr.get());
    }
}

执行代码,可以看到以下输出:

软引用对象oneObjectSr的地址:java.lang.ref.SoftReference@72ea2f77
通过oneObjectSr关联的oneObject对象的地址:com.esparks.pandora.learning.references.OneObject@33c7353a
数组的地址:[B@681a9515
正常gc一次之后,oneObject对象并没有回收。地址com.esparks.pandora.learning.references.OneObject@33c7353a
创建另一个大小为20m的数组otherArray
啊哦~OneObject被回收了
otherArray的地址:[B@3af49f1c
现在srObject的地址:java.lang.ref.SoftReference@19469ea2
现在srObject中oneObject对象的地址:null
刚才的数组对象也被回收啦,地址:null

弱引用

需要通过WeakReference对象实现:

WeakReference<OneObject> oneObjectWr = new WeakReference<>(new OneObject());

弱引用.png

只要发生gc,就会回收只存在弱引用的对象。

常用于Threadlocal。

上demo,注意注释

/**
 * 弱引用
 * 只要gc就会回收
 *
 * @author 
 * @date 2020-05-23
 */
public class ShowWeakReference {
    public static void main(String[] args) {
        // 我们需要通过WeakReference来创建弱引用
        WeakReference<OneObject> objectWr = new WeakReference<>(new OneObject());
        System.out.println("弱引用objectWr的地址:" + objectWr);
        System.out.println("弱引用objectWr关联的oneObject对象的地址:" + objectWr.get());
        System.gc();
        // gc后,弱引用对象还在,但是通过弱引用对象创建的对象就被回收了
        System.out.println("gc后,弱引用objectWr的地址:" + objectWr);
        System.out.println("gc后,弱引用objectWr关联的oneObject对象的地址:" + objectWr.get());
    }
}

执行代码,可以看到以下输出:

弱引用objectWr的地址:java.lang.ref.WeakReference@72ea2f77
弱引用objectWr关联的oneObject对象的地址:com.esparks.pandora.learning.references.OneObject@33c7353a
gc后,弱引用objectWr的地址:java.lang.ref.WeakReference@72ea2f77
gc后,弱引用objectWr关联的oneObject对象的地址:null
啊哦~OneObject被回收了

虚引用

需要通过PhantomReference对象和ReferenceQueue实现:

private ReferenceQueue<OneObject> queue = new ReferenceQueue<>();
PhantomReference<OneObject> oneObjectPr = new PhantomReference<>(new OneObject(), queue);

虚引用.png

无论是否gc,其实都获取不到通过PhantomReference创建的对象。

其仅用于管理直接内存,起到通知的作用。

这里补充一下背景。因为垃圾回收器只能管理JVM内部的内存,无法直接管理系统内存的。对于一些存放在系统内存中的数据,JVM会创建一个引用指向这部分内存。

jvmgc.png

当这个引用在回收的时候,就需要通过虚引用来管理指向的系统内存。这里还需要依赖一个队列来实现。当触发gc对一个虚引用对象回收时,会将虚引用放入创建时指定的ReferenceQueue中。之后单独对这个队列进行轮训,并做额外处理。

jvmgc2.png


上demo,注意注释

/**
 * 虚引用
 * 只用于管理直接内存,起到通知的作用
 *
 * @author 
 * @date 2020-05-23
 */
public class ShowPhantomReference {
    /**
     * 虚引用需要的队列
     */
    private static final ReferenceQueue<OneObject> QUEUE = new ReferenceQueue<>();
    public static void main(String[] args) {
        // 我们需要通过WeakReference来创建虚引用
        PhantomReference<OneObject> objectPr = new PhantomReference<>(new OneObject(), QUEUE);
        System.out.println("虚引用objectPr的地址:" + objectPr);
        System.out.println("虚引用objectPr关联的oneObject对象的地址:" + objectPr.get());
        // 触发gc,然后检查队列中是否有虚引用
        while (true) {
            System.gc();
            Reference<? extends OneObject> poll = QUEUE.poll();
            if (poll != null) {
                System.out.println("队列里找到objectPr啦" + poll);
                break;
            }
        }
    }
}

执行代码,可以看到以下输出:

虚引用objectPr的地址:java.lang.ref.PhantomReference@73ea3f33
虚引用objectPr关联的oneObject对象的地址:null
啊哦~OneObject被回收了
队列里找到objectPr啦java.lang.ref.PhantomReference@73ea2f33
上一篇: java线程切换消耗时间排查-借助top指令对cpu消耗分析
下一篇: 内存泄漏情况和示例 ( 出现FullGC内存泄漏问题排查和分析)
推荐文章
  • 架构师在进行系统设计时,遵循一套复杂且综合的方法论,主要包括以下核心步骤:需求分析:理解并明确业务需求是架构设计的第一步。架构师需要与各利益相关者深入沟通,收集和分析业务需求、性能需求、安全性需求、扩展性需求等。领域建模:基于需求分析,构建抽象的业务模型或数据模型,明确系统的边界、核心实体及其关系。
  • 根据阿里交易型业务的特点,以及在双十一这样业内罕有的需求推动下,我们在官方的MySQL基础上增加了非常多实用的功能、性能补丁。而在使用MySQL的过程中,数据一致性是绕不开的话题之一。本文主要从阿里巴巴“去IOE”的后时代讲起,向大家简单介绍下我们过去几年在MySQL数据一致性上的努力和实践,以及目
  • 随着深度学习在图像、语言、广告点击率预估等各个领域不断发展,很多团队开始探索深度学习技术在业务层面的实践与应用。而在广告CTR预估方面,新模型也是层出不穷:WideandDeep、DeepCrossNetwork、DeepFM、xDeepFM,美团很多篇深度学习博客也做了详细的介绍。但是,当
  • 1.背景搜索优化问题,是个典型的AI应用问题,而AI应用问题首先是个系统问题。经历近10年的技术积累和沉淀,美团搜索系统架构从传统检索引擎升级转变为AI搜索引擎。当前,美团搜索整体架构主要由搜索数据平台、在线检索框架及云搜平台、在线AI服务及实验平台三大体系构成。在AI服务及实验平台中,模型训练平台
  • 行业算法版简介OpenSearch-行业算法版是基于阿里巴巴自主研发的大规模分布式搜索引擎搭建的一站式智能搜索业务开发平台,目前为包括淘宝、天猫在内的阿里集团核心业务提供搜索服务支持。通过内置各行业的查询语义理解、机器学习排序算法等能力,提供充分开放的引擎能力,助力开发者快速搭建智能搜索服务。Ope
  • 一.概述我们在考虑MySQL数据库的高可用的架构时,主要要考虑如下几方面:如果数据库发生了宕机或者意外中断等故障,能尽快恢复数据库的可用性,尽可能的减少停机时间,保证业务不会因为数据库的故障而中断。用作备份、只读副本等功能的非主节点的数据应该和主节点的数据实时或者最终保持一致。当业务发生数据库切换时
学习大纲