软引用和弱引用的区别_强、软、弱、虚引用的区别和使用

38c48a32d4e74a23bfa8ee788dd019ba.png

原文阅读:

强、软、弱、虚引用的区别和使用​mp.weixin.qq.com
4b7b3996da6a929ff0f7c9fac6b5192f.png

Java提供了四种级别的应用类型:强引用、软引用、弱引用及虚引用。那么这四种引用类型有什么区别呢?

首先我们通过一张图来看看四种引用在Java中的表示:

c7e4215bd3b07b0b229abcb8a1f90e1d.png

FinalReference

由于FinalReference是包内可见,Finalizer是其唯一的扩展类。在外部是无法直接使用这两个类的,因为FinalReference引用类型是为JVM提供的,JVM会对那些实现了 Object 中 finalize() 方法的类实例化一个对应的FinalReference,提供 对象被 GC 前需要执行 finalize 方法的对象 的机制。这里不详细介绍。

强引用(StrongReference)

强引用在 java.lang.ref 中并没有实际的对应类型,但我们程序中几乎所有的引用使用的都是强引用。

StringBuilder sb = new StringBuilder();

9f44f89d58fb653e848bf5700f99ee3c.png

上面通过在堆中创建实例,然后赋值给栈中局部变量 sb 的方式 就是 强引用。

强引用有如下特点:

  • 强引用可以直接访问目标对象
  • 强引用(存在)指向的对象任何时候都不会被回收,JVM宁愿抛出OOM异常,也不会回收。
  • 强引用可能会导致内存泄漏

注意: 为了尽量避免内存不足的情况,我们可以在变量sb使用后通过显示的将变量sb置为null,来加速对象的回收。

解释: 1. 内存溢出(out of memory) 是指 程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory.

  1. 内存泄漏(memory leak) 是指 程序申请内存后,无法释放已申请的内存空间,这样的泄漏积少成多,memory leak 会导致 out of memory .

软引用(SoftReference)

软引用对应的类为 java.lang.ref.SoftReference, 一个软引用中的对象,不会很快被JVM回收,JVM会根据当前堆的使用情况来判断何时回收,当堆的使用率超过阈值时,才回去回收软引用中的对象。

先通过一个例子来了解一下软引用:

Object obj = new Object();
SoftReference softRef = new SoftReference<Object>(obj);
//删除强引用
obj = null;
//调用gc
System.gc();
System.out.println("gc之后的值:" + softRef.get()); // 对象依然存在

软引用也可以和一个引用队列联合使用,如果软引用中的对象(obj)被回收,那么软引用会被 JVM 加入关联的引用队列中。

ReferenceQueue<Object> queue = new ReferenceQueue<>();
Object obj = new Object();
SoftReference softRef = new SoftReference<Object>(obj,queue);
//删除强引用
obj = null;
//调用gc
System.gc();
System.out.println("gc之后的值: " + softRef.get()); // 对象依然存在
//申请较大内存使内存空间使用率达到阈值,强迫gc
byte[] bytes = new byte[100 * 1024 * 1024];
//如果obj被回收,则软引用会进入引用队列
Reference<?> reference = queue.remove();
if (reference != null){System.out.println("对象已被回收: "+ reference.get());  // 对象为null
}

引用队列(ReferenceQueue)作用

Queue的意义在于我们在外部可以对queue中的引用进行监控,当引用中的对象被回收后,我们可以对引用对象本身继续做一些清理操作,因为我们引用对象(softRef)也占有一定的资源。

弱引用(WeakReference)

弱引用中的对象具有很短的声明周期,因为在系统GC时,只要发现弱引用,不管堆空间是否足够,都会将对象进行回收。由于垃圾回收器是一个优先级很低的线程,因此不一定很快发现那些只具有弱引用的对象。

弱引用的简单使用:

Object obj = new Object();
WeakReference weakRef = new WeakReference<Object>(obj);
//删除强引用
obj = null;
System.out.println("gc之后的值:" + weakRef.get()); // 对象依然存在
//调用gc
System.gc();
System.out.println("gc之后的值:" + weakRef.get()); // 对象为null

弱引用也可以和一个引用队列联合使用,如果弱引用中的对象(obj)被回收,那么软引用会被 JVM 加入关联的引用队列中。

ReferenceQueue<Object> queue = new ReferenceQueue<>();
Object obj = new Object();
WeakReference weakRef = new WeakReference<Object>(obj,queue);
//删除强引用
obj = null;
System.out.println("gc之后的值: " + weakRef.get()); // 对象依然存在
//调用gc
System.gc();
//如果obj被回收,则软引用会进入引用队列
Reference<?> reference = queue.remove();
if (reference != null){System.out.println("对象已被回收: "+ reference.get());  // 对象为null
}
软引用和弱引用都非常适合保存那些可有可无的缓存数据,当内存不足时,缓存数据被回收(再通过备选方案查询),当内存充足时,也可以存在较长时间,起到加速的作用。

应用

  • WeakHashMap

当key只有弱引用时,GC发现后会自动清理键和值,作为简单的缓存表解决方案。

  • ThreadLocal

ThreadLocal.ThreadLocalMap.Entry 继承了弱引用,key为当前线程实例,和WeakHashMap基本相同。

虚引用(PhantomReference)

虚引用 就是 形同虚设 ,它并不能决定 对象的生命周期。任何时候这个只有虚引用的对象都有可能被回收。因此,虚引用主要用来跟踪对象的回收,清理被销毁对象的相关资源。PhantomReference的 get() 方法永远返回null ,而且只提供了与引用队列同用的构造函数。所以虚引用必须和引用队列一同使用。

Map<Object, String> map = new HashMap<>();
ReferenceQueue<Object> queue = new ReferenceQueue<>();
Object obj = new Object();
PhantomReference phantomRef = new PhantomReference<Object>(obj,queue);
map.put(obj,"obj val");
new CheckRefQueue(queue,map).start();
//删除强引用
obj = null;
Thread.sleep(1000);
int i = 1;
while (true){System.out.println("第"+i+"次gc");System.gc();Thread.sleep(1000);
}
public class CheckRefQueue extends Thread {private ReferenceQueue queue;private Map<Object, String> map;public CheckRefQueue(ReferenceQueue queue, Map<Object, String> map) {this.queue = queue;this.map = map;}@Overridepublic void run() {// 等待,直到对象呗回收Reference reference = queue.remove();// 释放引用对象的引用map.remove(reference.get());}
}

总结

c1174258232af0896c8f3ff4d02ccc2b.png

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

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

相关文章

python文本文件不能用二进制文件方式读入_如何使用python函数以二进制形式读取文件?...

虽然读取文件的方式各种各样&#xff0c;但是通过二进制&#xff0c;还是头一次&#xff0c;实现过过程并不难&#xff0c;我们需要将文件先做好封存&#xff0c;以函数的形式&#xff0c;保存下来&#xff0c;然后直接导入进行使用&#xff0c;这样就可以读取文件&#xff0c;…

一组数字中算出最相近的组合_据说在金字塔里发现的这组数字,貌似是通往宇宙的密码...

我们都知道阿拉伯数字是全世界都在用的计数单位的数字&#xff0c;我们的生活离不开阿拉伯数字&#xff0c;其广泛性很大。比如买菜、买衣服。做数学题等等都需要用到。不过呢早前有人称在埃及金字塔内发现了一组数字142857&#xff0c;这组数字貌似就是通往宇宙的密码。这一说…

前端悬浮窗效果_Flutter自绘组件:微信悬浮窗(一)

看微信公众号的时候时常会想退出去回复消息&#xff0c;但又不想放弃已经阅读一半的文章&#xff0c;因为回复信息后再从公众号找到该篇文章之间有不必要的时间花费&#xff0c;微信悬浮窗的出现解决了这个烦恼&#xff0c;回复完消息之后只需要点击悬浮窗就可以回到之前在阅读…

date类型_Quartz与Date---cron的相互转换

产生原因:因为项目最近设计到了一个Quartz相关的模块&#xff0c;前端需要传递时间参数到后台, 然后后台设置一个新的定时任务, 所以后台需要一个可以实现Date与cron之间的相互转换(因为Quartz需要的Cron格式的数据)&#xff0c;所以就借助java的SimpleDateFormat的格式化,然后…

vbs if 不等于_6、if语句和关系表达式

示例3.1&#xff1a;星星公司致力于信件快递业务&#xff0c;收费标准是&#xff1a;500g以内6元&#xff0c;超过500g9元。应该就是输入重量&#xff0c;显示钱&#xff0c;那可以用cout和cin&#xff0c;如果w小于500&#xff0c;c是6&#xff0c;否则&#xff0c;c是9。//pr…

python文件是怎么写_python头文件怎么写

本文主要以python2为例。首先介绍一下Python头文件的编程风格&#xff0c;然后再给大家详细介绍import部分的基本用法。这两个部分就是Python中头文件的组成模块。编程风格#!/usr/bin/env python #在文件头部 ( 第一行 ) 加上 设置 Python 解释器 # -*- coding: utf-8 -*- #在文…

【学习笔记】第二章——处理机调度的概念、层次、时机、切换过程 调度方式、调度算法的指标

文章目录一. 概念 & 层次1. 高级调度&#xff08;作业调度&#xff09;2. 中级调度&#xff08;内存调度&#xff09;挂起态 & 七状态模型3. 低级调度&#xff08;进程调度&#xff09;4. 三种调度的对比联系 && 总结二. 时机、切换过程 & 调度方式1. 进程…

formdata上传文件_关于multipart/formdata上传文件

最近在做一个文件上传的开放接口&#xff0c;用到Content-Type: multipart/form-data这种请求类型&#xff0c;特地做了一些研究和记录。在最初的 http协议中&#xff0c;并没有上传文件方面的功能。RFC1867为 http协议添加了这个能力。常见的浏览器&#xff0c;如 Microsoft I…

【学习笔记】第二章——调度算法:先来先服务FCFS、短作业优先SJF、高响应比HRRN

文章目录一. 先来先服务&#xff08;FCFS&#xff09;二. 短作业优先&#xff08;SJF&#xff09;三. 高响应比优先1. 对前面两种算法的思考2. 描述四. 一、二、三总结例子都要手动写一遍哦&#xff5e;这三个是供早期的批处理系统使用的算法 一. 先来先服务&#xff08;FCFS&a…

【学习笔记】第二章——时间片轮转RR、优先级调度、多级反馈队列调度算法

文章目录一. 时间片轮转二. 优先级调度三. 多级反馈队列调度算法四. 总结一. 时间片轮转 公平&#xff0c;轮流给进程提供时间片只用于进程调度&#xff08;只有进程才能被分配时间片&#xff09;抢占式&#xff0c;由时钟装置发出时钟中断来通知**缺点&#xff1a;**高频的进…

laravel 分词搜索匹配度_elasticsearch基础笔记9-elasticsearch 词项全文搜索

es的核心功能就是搜索和分析。那么我们看看搜索相关内容1、搜索机制在进入搜索之前&#xff0c;会对查询体根据情况进行分析和处理。2、有哪些常用搜索类型全文查询 词项查询 复合查询 嵌套查询 位置查询 特殊查询等。我们常用到的就是前三种&#xff0c;学起来简单&#xff0c…

【学习笔记】第二章——进程同步、进程互斥、进程互斥的硬件/软件实现方法

文章目录一. 进程同步 && 进程互斥四个区域四个原则总结&#xff1a;二. 进程互斥的软件实现方法1&#xff09;单标志法2&#xff09;双标志先检查法3&#xff09;双标志后检查法4&#xff09;Peterson 算法总结三. 进程互斥的硬件实现方法1&#xff09;中断屏蔽方法2&…

python的数据结构包括那些_python算法与数据结构-什么是数据结构

一、什么是数据结构 数据结构&#xff0c;直白地理解&#xff0c;就是研究数据的存储方式。 我们知道&#xff0c;数据存储只有一个目的&#xff0c;即为了方便后期对数据的再利用&#xff0c;就如同我们使用数组存储 {1,2,3,4,5} 是为了后期取得它们的值&#xff0c;因此&…

seo自动发外链_一套节约成本全网营销方案-小小课堂SEO培训教程

很多公司都是由一些小型工作室或个人工作室慢慢发展而来的&#xff0c;在这过程中&#xff0c;人员、资金链、资源、项目等因素一旦出现问题&#xff0c;可能会导致项目失败&#xff0c;那么在互联网上投入的资金如果过多&#xff0c;可能都是白白打了水漂。今天&#xff0c;小…

python 支付宝个人账单_金融支付财务融合业务-实践分享1:订单、账单、交易流水、账套知识解构、原理解析...

本文作者从实际工作实践出发&#xff0c;结合案例等分享了电商金融支付财务融合中的基本概念和相关原理解析&#xff0c;包括&#xff1a;订单、账单、交易流水和账知识解构&#xff0c;供大家一同参考和学习。从事电商、进销存、金融、支付、财务的产品同学&#xff0c;是否对…

【学习笔记】第二章——信号量机制 用信号量实现互斥、同步

文章目录一. 信号量机制整型信号量记录型信号量例子&#xff1a;总结二. 用信号量实现互斥、同步互斥同步前驱总结一. 信号量机制 信号量&#xff1a;一个用于表示系统中某种资源的数量的变量&#xff08;整数 or 记录型变量&#xff09;一对原语&#xff1a;wait(S) 和 signa…

opengl 安装_一步步学OpenGL(34) -《GLFX,一个OpenGL效果库》

教程 34GLFX,一个OpenGL效果库原文&#xff1a; http://ogldev.atspace.co.uk/www/tutorial34/tutorial34.htmlCSDN完整版专栏&#xff1a; https://blog.csdn.net/cordova/article/category/9266966理论介绍这篇教程暂时先不继续探索OpenGL的特性和3D技术了&#xff0c;来介绍…

【LeetCode笔记】剑指 Offer 60. n个骰子的点数(Java、动态规划)

文章目录题目描述代码 & 思路1. 二维数组&#xff08;方便理解&#xff09;2. 一维数组&#xff08;节约空间&#xff09;二刷鸽了好久的打题博客&#xff5e;要继续补起来了&#xff01; 今天不打题&#xff0c;明天变垃圾 QAQ 题目描述 一眼就想先暴力枚举、或者递归呀&…

java 根据圆心计算圆弧上点的经纬度_【控制测量学】-高斯投影正算公式以及java代码

正算公式(将经纬度转化为坐标):java代码(附有源代码和修改后的代码):源代码:/** * 由经纬度反算成高斯投影坐标 * * param longitude * param latitude * return */ public static double[] GaussToBLToGauss( double longitude, double latitude) { …

【LeetCode笔记】剑指 Offer 59 - II. 队列的最大值(Java、辅助队列)

文章目录题目描述思路 && 代码二刷题目描述 恢复打题的第二天打卡&#xff5e; 可以说是这道最小栈的兄弟题目了&#xff0c;很相似总体思路还是一样&#xff0c;靠空间换时间&#xff5e;也就是借助辅助队列 思路 && 代码 这篇题解的动图做得很好&#xff…