Java——》4种引用:强软弱虚

news2024/11/28 2:47:20

推荐链接:
    总结——》【Java】
    总结——》【Mysql】
    总结——》【Redis】
    总结——》【Kafka】
    总结——》【Spring】
    总结——》【SpringBoot】
    总结——》【MyBatis、MyBatis-Plus】
    总结——》【Linux】
    总结——》【MongoDB】
    总结——》【Elasticsearch】

引用的定义:
1.我们的数据类型必须是引用类型
2.我们这个类型的数据所存储的数据必须是另外一块内存的起始地址

image.png

一、NormalReference = 强 = 普通 = 默认

强引用是平常中使用最多的引用,强引用在程序内存不足(OOM)的时候也不会被回收

import java.io.IOException;

public class T01_NormalReference {
    public static void main(String[] args) throws IOException {
        // 强引用 = 普通引用 = 默认引用,只要有一个引用指向这个对象,那么GC一定不会回收它
        M m = new M();
        // 把m设置为null,就不会再有引用引用M这个对象,也就是说把m和new M()之间的引用给打断了,不再有关联了,这时候再运行程序 ,会发现M对象被GC回收了
        //m = null;
        System.gc(); //DisableExplicitGC,显示调用GC
        // 要在最后阻塞当前线程,因为GC是跑在别的线程的,如果main线程直接退出了,那GC就没什么意义了
        // 阻塞当前线程,就是让当前整个程序不会停止
        System.in.read();
    }

    static class M {
        @Override
        // GC的时候,会调用 finalize()
        // 这里重写finalize(),只是为了观察什么时候被GC,所以这个方法永远不需要重写,而且也不应该被重写
        protected void finalize() throws Throwable {
            System.out.println("finalize");
        }
    }
}

二、SoftReference = 软

软引用在程序内存不足时,会被回收

/**
 * 软引用
 * 软引用是用来描述一些还有用但并非必须的对象。
 * 对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收。
 * 如果这次回收还没有足够的内存,才会抛出内存溢出异常。
 *
 * 当有一个对象,被软引用指向时,只有系统内存不够用时候,GC才会回收,内存够用GC不会回收
 *
 * 软引用非常适合缓存使用
 *
 * 注意:在程序运行前,设置一下堆内存最大为20M
 * 参数:-Xms20M -Xmx20M
 */
import java.lang.ref.SoftReference;

public class T02_SoftReference {
    public static void main(String[] args) {
        // 字节数组分配10M
        // 栈里面有个m,指向堆里的软引用SoftReference,软引用又指向了10M的字节数组
        SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);
        // m.get(),拿到字节数组,打印的是hashcode值
        System.out.println(m.get()); // 打印结果:[B@2344fc66
        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 如果被回收,m.get() = null
        // 如果没回收,m.get() = 字节数组的hashcode值
        System.out.println(m.get());// 打印结果为:[B@2344fc66,虽然调用了GC,但是对象并没有被回收,因为堆内存够用

        //再分配一个数组15M,heap将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用干掉
        byte[] b = new byte[1024*1024*15];
        // 如果被回收,m.get() = null
        // 如果没回收,m.get() = 字节数组的hashcode值
        System.out.println(m.get());// 打印结果:null,因为堆空间不够用,GC把软引用给回收了

    }
}

三、WeakReference = 弱

弱引用就是只要JVM垃圾回收器发现了它,就会将之回收

/**
 * 弱引用遭到gc就会回收
 * 如果有一个强引用指向了这个弱引用之后,只要这个强引用消失了,这个弱引用就应该被回收,一般用在容器里,最典型的就是ThreadLocal

 * ThreadLocal<M> tl = new ThreadLocal<>();
 * tl.set(new M());
 *
 * 1、哪里可以看出Entry的key是弱引用?
 * 往当前线程的threadLocals变量设置一个Entry,key是ThreadLocal对象,value是M对象
 * 由于Entry的父类是WeakReference,里面装的是ThreadLocal对象,调用了super(key),相当于new WeakReference(key),
 * 所以key是通过弱引用指向的ThreadLocal对象
 *
 * 2、为什么Entry要使用弱引用?
 * 当前线程是我们的main线程,tl是强引用指向ThreadLocal对象,tl是个局部变量,方法结束它就消失了。
 * 如果这个ThreadLocal对象还被一个强引用的key指向的时候,那这个ThreadLocal对象就回收不了了。
 * 而且由于很多线程是长期存在的,这个Map就会长期存在,那这个ThreadLocal对象永远不会被消失,就可能会出现内存泄漏。
 *
 * 但如果这个key是弱引用的话,就不会存在内存泄漏的问题,只要这个强引用消失了,这个弱引用就被回收了。
 *
 * 3、ThreadLocal为什么会出现内存泄漏?
 * tl是强引用指向ThreadLocal对象,tl是个局部变量,方法结束它就消失了。
 * 由于key是通过弱引用指向ThreadLocal对象,这时候key的指向也被回收了,key变成了null。
 * 由于这个threadLocals的Map是一直存在的,但key变成null了,那value就永远访问不到了,
 * 如果这个Map积累的越来越多,它还是会内存泄漏,所以ThreadLocal里面的对象不用了,一定要remove掉,不然还是会有内存泄漏。
 */

import java.lang.ref.WeakReference;

public class T03_WeakReference {
    public static void main(String[] args) {

        WeakReference<M> m = new WeakReference<>(new M());
        // 打印结果:com.mashibing.juc.c_022_RefTypeAndThreadLocal.T03_WeakReference$M@458ad742
        System.out.println(m.get());
        System.gc();
        // 打印结果:null,因为弱引用一定会被GC回收
        System.out.println(m.get());

        // tl是通过强引用指向的ThreadLocal对象
        ThreadLocal<M> tl = new ThreadLocal<>();
        // key是通过弱引用指向的ThreadLocal对象
        tl.set(new M());
        // 一定要remove,不然会发生内存泄漏
        tl.remove();
    }
    static class M {
        @Override
        // GC的时候,会调用 finalize()
        // 这里重写finalize(),只是为了观察什么时候被GC,所以这个方法永远不需要重写,而且也不应该被重写
        protected void finalize() throws Throwable {
            System.out.println("finalize");
        }
    }
}


四、PhantomReference = 虚

虚引用的回收机制跟弱引用差不多,但是它被回收之前,会被放入 ReferenceQueue 中。注意哦,其它引用是被JVM回收后才被传入 ReferenceQueue 中的。由于这个机制,所以虚引用大多被用于引用销毁前的处理工作。还有就是,虚引用创建的时候,必须带有 ReferenceQueue

/**
 *
 *
 *     一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,
 *     也无法通过虚引用来获取一个对象的实例。
 *     为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
 *     虚引用和弱引用对关联对象的回收都不会产生影响,如果只有虚引用活着弱引用关联着对象,
 *     那么这个对象就会被回收。它们的不同之处在于弱引用的get方法,虚引用的get方法始终返回null,
 *     弱引用可以使用ReferenceQueue,虚引用必须配合ReferenceQueue使用。
 *
 *     jdk中直接内存的回收就用到虚引用,由于jvm自动内存管理的范围是堆内存,
 *     而直接内存是在堆内存之外(其实是内存映射文件,自行去理解虚拟内存空间的相关概念),
 *     所以直接内存的分配和回收都是有Unsafe类去操作,java在申请一块直接内存之后,
 *     会在堆内存分配一个对象保存这个堆外内存的引用,
 *     这个对象被垃圾收集器管理,一旦这个对象被回收,
 *     相应的用户线程会收到通知并对直接内存进行清理工作。
 *
 *     事实上,虚引用有一个很重要的用途就是用来做堆外内存的释放,
 *     DirectByteBuffer就是通过虚引用来实现堆外内存的释放的。
 *
 */
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.LinkedList;
import java.util.List;

public class T04_PhantomReference {
    private static final List<Object> LIST = new LinkedList<>();
    private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();



    public static void main(String[] args) {


        PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE);


        new Thread(() -> {
            while (true) {
                LIST.add(new byte[1024 * 1024]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
                // 打印的结果:null,虚引用是get不到值,但弱引用是可以get到值的
                System.out.println(phantomReference.get());
            }
        }).start();

        new Thread(() -> {
            while (true) {
                Reference<? extends M> poll = QUEUE.poll();
                if (poll != null) {
                    System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);
                }
            }
        }).start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

五、四种引用的区别

1、写法

引用写法
M m = new M();
SoftReference<byte[]> m = new SoftReference<>(new byte[1024102410]);
WeakReference m = new WeakReference<>(new M());
方式一:
private static final ReferenceQueue QUEUE = new ReferenceQueue<>();
PhantomReference phantomReference = new PhantomReference<>(new M(), QUEUE);
方式二:
PhantomReference prf = new PhantomReference(new M(),new ReferenceQueue<>());

2、回收机制

引用回收机制
只要有一个引用指向这个对象,那么GC一定不会回收它
只有系统内存不够用的时候,GC才会回收这个对象,内存够用GC不会回收。
只要GC,就会回收
只要GC,就被回收,这个虚引用会装到这个队列Queue里,然后接收到一个通知,一般监听GC回收阶段,或者是回收堆外内存时使用。

3、使用场景

引用使用场景
平常中使用最多
创建缓存的时候,创建的对象放进缓存中,当内存不足时,JVM就会回收早先创建的对象。
Java源码中的 java.util.WeakHashMap 中的 key 就是使用弱引用,一旦我不需要某个引用,JVM会自动帮我处理它,这样我就不需要做其它操作。可以解决内存泄漏的问题。
用于引用销毁前的处理工作,比如说资源释放或者回收堆外内存等。 Object.finalize() 虽然也可以做这类动作,但是这个方式即不安全又低效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1177182.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flume从入门到精通一站式学习笔记

文章目录 什么是FlumeFlume的特性Flume高级应用场景Flume的三大核心组件Source&#xff1a;数据源channelsink Flume安装部署Flume的使用案例&#xff1a;采集文件内容上传至HDFS案例&#xff1a;采集网站日志上传至HDFS 各种自定义组件例如&#xff1a;自定义source例如&#…

什么洗地机好?洗地机品牌排行榜

近年来&#xff0c;比较热门的家具清洁工具非洗地机莫属了&#xff0c;其中缘由莫过于洗地机集合了扫地、洗地、吸尘等功能&#xff0c;可以同时处理干湿垃圾&#xff0c;可以轻松应对顽固污渍&#xff0c;是非常高效又省力的清洁工具&#xff0c;那么面对雨后春笋般的洗地机市…

centos7安装nginx-阿里云服务器

1.背景 2.准备工作步骤 2.1.安装gcc 阿里云服务器一般默认是安装了的 检查是否已安装 gcc -v 出现如下信息表示已安装: 如果没有安装,执行 yum -y install gcc 2.2.安装pcre,pcre-devel yum install -y pcre pcre-devel 2.3.安装zlib yum install -y zlib zlib-devel…

使用WMS仓储管理系统防止呆料的几个建议

随着互联网的深入&#xff0c;客户的需求变化迅速&#xff0c;从淘宝、京东到直播带货&#xff0c;产品的更新迭代速度越来越快。对于制造企业而言&#xff0c;如何在这样的环境中降低呆腐物料&#xff0c;提高利润&#xff0c;是其生存和发展的关键。 面对快速迭代的产品&…

通过GFlags工具来复现因为野指针、内存越界等造成的程序崩溃

系列文章目录 C程序异常调查专栏 文章目录 系列文章目录前言一、GFlags是什么&#xff1f;二、如何获取GFlags三、使用步骤1.确认GFlags是否已经安装2.以管理员权限启动Command prompt3.GFlags有效设定4.检查GFlags有效设定是否成功5.根据客户复现步骤运行程序 总结 前言 客户…

MQTT协议基础学习

MQTT是什么 MQTT是一个客户端服务端架构的发布/订阅模式的消息传输协议。 MQTT基本原理 MQTT服务端 MQTT服务端通常是一台服务器&#xff0c;可对MQTT信息的接收、储存、处理和发送。负责将MQTT客户端发送来的信息传递给其他MQTT客户端&#xff08;需要客户端订阅&#xff…

骨传导蓝牙耳机哪款好?这五款高品质骨传导耳机不可错过!

随着耳机的使用频率增加&#xff0c;骨传导耳机也走进了越来越多人的视野里&#xff0c;而传统的入耳式耳机&#xff0c;常常以使用场景少、佩戴会疼痛、容易引发耳部疾病等原因逐渐被骨传导耳机所替代&#xff0c;所以现在有越来越多的人去选择骨传导耳机&#xff0c;但要注意…

【Leetcode】349. 两个数组的交集

题意 给定两个数组&#xff0c;编写一个函数来计算它们的交集。 说明&#xff1a; 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。 思路 这道题目&#xff0c;主要要学会使用一种哈希数据结构&#xff1a;unordered_set&#xff0c;这个数据结构可以解决…

供应链云仓系统:实现采购、销售、收银、路线规划一体化,高效协同,再创商业价值!

供应链云仓系统是一款集合采购、销售、收银、路线规划等多项功能的软件系统&#xff0c;旨在帮助企业实现业务流程的全面自动化和协同化。通过该系统&#xff0c;企业可以轻松管理供应链的各个环节&#xff0c;提高运营效率&#xff0c;降低成本&#xff0c;实现商业价值的最大…

标讯通:无代码开发连接API,为广告推广与客服系统集成新商机

无代码开发连接API的新趋势——标讯通 招投标已成为大多数企业获取业务的主要途径之一。然而&#xff0c;由于招标信息平台分散&#xff0c;平台发布的招标信息更是有数十万条&#xff0c;单纯依赖人工查询&#xff0c;往往过程繁琐&#xff0c;效率低下。在这样的背景下&…

java智能在线考试系统源码 基于SpringBoot+Vue开发

java智能在线考试系统源码 基于SpringBootVue开发 环境介绍 语言环境&#xff1a;Java: jdk1.8 数据库&#xff1a;Mysql: mysql5.7 应用服务器&#xff1a;Tomcat: tomcat8.5.31 开发工具&#xff1a;IDEA或eclipse 开发技术&#xff1a;SpringbootVue 项目简介&…

再也不愁了!有了它在家也能轻松制作个人作品

​在家就能轻松制作个人作品&#xff0c;这不仅节省了时间和精力&#xff0c;还降低了成本。无论你是想要制作一个短片、设计一款App、还是写一篇文章&#xff0c;这个网站都能提供专业的支持和帮助。 1.在浏览器搜索FLBOOK在线制作电子杂志平台&#xff0c;点击登录与注册 2.点…

CV计算机视觉每日开源代码Paper with code速览-2023.11.2

精华置顶 墙裂推荐&#xff01;小白如何1个月系统学习CV核心知识&#xff1a;链接 点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【目标检测】Re-Scoring Using Image-Language Similarit…

ubuntu20.04 安装cudnn

中文地址是.cn&#xff1a;cuDNN 历史版本 | NVIDIA 开发者 英文地址是.com&#xff1a;cuDNN 历史版本 | NVIDIA 开发者 1、下载cudnn&#xff1a;cudnn-local-repo-ubuntu2004-8.8.1.3_1.0-1_amd64.deb 解压并安装&#xff1a;sudo dpkg -i cudnn-local-repo-ubuntu2004-8.8…

配件管理系统软件哪家好?如何优化企业设备管理,提高运营效率?

随着企业运营的日益复杂化&#xff0c;设备的维修维护与管理已成为企业生产运营中的重要环节。在这个过程中&#xff0c;配件的管理往往成为一项极具挑战性的任务。如何有效地管理备用的配件&#xff0c;缩短维修的时间&#xff0c;同时防止库存积压&#xff0c;是许多企业目前…

有什么好用的CRM客户管理系统?推荐这5大高口碑的CRM系统!

有什么好用的CRM客户管理系统&#xff1f;推荐这5大高口碑的CRM系统&#xff01; 好用的CRM客户管理系统&#xff1a; ①需要进行精细化管理 ②需要专业的管理工具 ③最好能够做到和erp系统和oa系统的集成 授人以鱼不如授人以渔&#xff0c;在给题主推荐crm系统之前&#…

Java前后端分离的在线考试系统源码

Java前后端分离的在线考试系统源码 技术栈 1&#xff0c;SpringBoot 2&#xff0c;Mybatis-plus 3&#xff0c;MySQL 5.7 4&#xff0c;Vue全家桶 5&#xff0c;ElementUI 6&#xff0c;Redis 7&#xff0c;Swagger 8&#xff0c;阿里云OSS 9&#xff0c;Log4j 考…

Linux网络编程04

更高效的零拷贝 发送方过程零拷贝 sendfile 发送文件方的零拷贝&#xff0c;虽然之前我们就可以使用mmap来实现零拷贝但是存在一个方法sendfile也可以直接实现数据从内核区发送到网络发送区socket 直接把内核里面你的文件数据不经过用户态&#xff0c;直接发送给另外一个文件…

成集云 | 电商平台、ERP、WMS集成 | 解决方案

电商平台ERPWMS 方案介绍 电商平台即是一个为企业或个人提供网上交易洽谈的平台。企业电子商务平台是建立在Internet网上进行商务活动的虚拟网络空间和保障商务顺利运营的管理环境&#xff1b;是协调、整合信息流、货物流、资金流有序、关联、高效流动的重要场所。企业、商家…

多功能声学综合馆:空间的“膜法师”

建筑是文明的承载者&#xff0c;是历史的见证者&#xff0c;也是城市的象征。但在现代都市中&#xff0c;我们不仅需要“固定”的建筑&#xff0c;更需要灵活与多功能性的空间。而这&#xff0c;正是多功能声学综合馆为我们带来的“膜法”。 不仅仅是建筑&#xff0c;更是艺术的…