Java:对象的强、软、弱和虚引用

java的自动化ruoyi模版框架 它基于经典的 Spring Boot 框架,集成了多种常用的开发组件,旨在帮助开发者快速构建各种应用程序。运行应用:运行 Spring Boot 应用的 main 方法或使用 IDE 运行配置。代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载。Shiro 或 Spring Security:安全框架,用于认证和授权。部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。config:配置类,用于配置 Spring 框架的各种组件。 阅读详情

转自:http://zhangjunhd.blog.51cto.com/113473/53092/


本文介绍对象的强、软、弱和虚引用的概念、应用及其在UML中的表示。
author: ZJ 07-12-1
Blog: [url]http://zhangjunhd.blog.51cto.com/[/url]

1.对象的强、软、弱和虚引用
在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。图1为对象应用类层次。
图1
⑴强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
 
⑵软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
 
⑶弱引用(WeakReference)
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
 
⑷虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
MyObject aRef = new  MyObject();
SoftReference aSoftRef=new SoftReference(aRef);
    此时,对于这个MyObject对象,有两个引用路径,一个是来自SoftReference对象的软引用,一个来自变量aReference的强引用,所以这个MyObject对象是强可及对象。
随即,我们可以结束aReference对这个MyObject实例的强引用:
MyObject anotherRef=(MyObject)aSoftRef.get();
    重新获得对该实例的强引用。而回收之后,调用get()方法就只能得到null了。
 
3.3 使用ReferenceQueue清除失去了软引用对象的SoftReference
作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,如:
SoftReference ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
    // 清除ref
}
理解了ReferenceQueue的工作机制之后,我们就可以开始构造一个Java对象的高速缓存器了。
 
3.4通过软可及对象重获方法实现Java对象的高速缓存
    利用Java2平台垃圾收集机制的特性以及前述的垃圾对象重获方法,我们通过一个雇员信息查询系统的小例子来说明如何构建一种高速缓存器来避免重复构建同一个对象带来的性能损失。我们将一个雇员的档案信息定义为一个Employee类:
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Hashtable;
public class EmployeeCache {
    static private EmployeeCache cache;// 一个Cache实例
    private Hashtable<String,EmployeeRef> employeeRefs;// 用于Chche内容的存储
    private ReferenceQueue<Employee> q;// 垃圾Reference的队列
 
    // 继承SoftReference,使得每一个实例都具有可识别的标识。
    // 并且该标识与其在HashMap内的key相同。
    private class EmployeeRef extends SoftReference<Employee> {
       private String _key = "";
 
       public EmployeeRef(Employee em, ReferenceQueue<Employee> q) {
           super(em, q);
           _key = em.getID();
       }
    }
 
    // 构建一个缓存器实例
    private EmployeeCache() {
       employeeRefs = new Hashtable<String,EmployeeRef>();
       q = new ReferenceQueue<Employee>();
    }
 
    // 取得缓存器实例
    public static EmployeeCache getInstance() {
       if (cache == null) {
           cache = new EmployeeCache();
       }
       return cache;
    }
 
    // 以软引用的方式对一个Employee对象的实例进行引用并保存该引用
    private void cacheEmployee(Employee em) {
       cleanCache();// 清除垃圾引用
       EmployeeRef ref = new EmployeeRef(em, q);
       employeeRefs.put(em.getID(), ref);
    }
 
    // 依据所指定的ID号,重新获取相应Employee对象的实例
    public Employee getEmployee(String ID) {
       Employee em = null;
       // 缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。
       if (employeeRefs.containsKey(ID)) {
           EmployeeRef ref = (EmployeeRef) employeeRefs.get(ID);
           em = (Employee) ref.get();
       }
       // 如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,
       // 并保存对这个新建实例的软引用
       if (em == null) {
           em = new Employee(ID);
           System.out.println("Retrieve From EmployeeInfoCenter. ID=" + ID);
           this.cacheEmployee(em);
       }
       return em;
    }
 
    // 清除那些所软引用的Employee对象已经被回收的EmployeeRef对象
    private void cleanCache() {
       EmployeeRef ref = null;
       while ((ref = (EmployeeRef) q.poll()) != null) {
           employeeRefs.remove(ref._key);
       }
    }
 
    // 清除Cache内的全部内容
    public void clearCache() {
       cleanCache();
       employeeRefs.clear();
       System.gc();
       System.runFinalization();
    }
}
4.使用弱引用构建非敏感数据的缓存
4.1全局 Map 造成的内存泄漏
无意识对象保留最常见的原因是使用Map将元数据与临时对象(transient object)相关联。假定一个对象具有中等生命周期,比分配它的那个方法调用的生命周期长,但是比应用程序的生命周期短,如客户机的套接字连接。需要将一些元数据与这个套接字关联,如生成连接的用户的标识。在创建Socket时是不知道这些信息的,并且不能将数据添加到Socket对象上,因为不能控制 Socket 类或者它的子类。这时,典型的方法就是在一个全局 Map 中存储这些信息,如下面的 SocketManager 类所示:使用一个全局 Map 将元数据关联到一个对象。
import java.util.WeakHashMap;
 
class Element {
    private String ident;
 
    public Element(String id) {
       ident = id;
    }
 
    public String toString() {
       return ident;
    }
 
    public int hashCode() {
       return ident.hashCode();
    }
 
    public boolean equals(Object obj) {
       return obj instanceof Element && ident.equals(((Element) obj).ident);
    }
   
    protected void finalize(){
       System.out.println("Finalizing "+getClass().getSimpleName()+" "+ident);
    }
}
 
class Key extends Element{
    public Key(String id){
       super(id);
    }
}
 
class Value extends Element{
    public Value (String id){
       super(id);
    }
}
 
public class CanonicalMapping {
    public static void main(String[] args){
       int size=1000;
       Key[] keys=new Key[size];
       WeakHashMap<Key,Value> map=new WeakHashMap<Key,Value>();
       for(int i=0;i<size;i++){
           Key k=new Key(Integer.toString(i));
           Value v=new Value(Integer.toString(i));
           if(i%3==0)
              keys[i]=k;
           map.put(k, v);
       }
       System.gc();
    }
}
从打印结果可以看出,当执行System.gc()方法后,垃圾回收器只会回收那些仅仅持有弱引用的Key对象。id可以被3整除的Key对象持有强引用,因此不会被回收。
 
4.3用 WeakHashMap 堵住泄漏
在 SocketManager 中防止泄漏很容易,只要用 WeakHashMap 代替 HashMap 就行了。(这里假定SocketManager不需要线程安全)。当映射的生命周期必须与键的生命周期联系在一起时,可以使用这种方法。用WeakHashMap修复 SocketManager。
<td )="" 0%="" 50%;="" padding-bottom:="" 0cm;="" border-left:="" windowtext="" 1pt="" solid;="" width:="" 426.1pt;="" padding-top:="" border-bottom:="" -moz-background-clip:="" -moz-initial;="" -moz-background-origin:="" -moz-background-inline-policy:="" -moz-initial"="" valign="top" width="568" style="padding: 0px 5.4pt; margin: 0px; border-right-color: windowtext; border-right-width: 1pt; border-right-style: solid; border-top-color: windowtext; border-top-width: 1pt; border-top-style: solid; ">
public class SocketManager {
    private Map<Socket,User> m = new WeakHashMap<Socket,User>();
   
    public void setUser(Socket s, User u) {
        m.put(s, u);
    }
    public User getUser(Socket s) {
        return m.get(s);
    }
}
 
4.4配合使用引用队列
WeakHashMap 用弱引用承载映射键,这使得应用程序不再使用键对象时它们可以被垃圾收集,get() 实现可以根据WeakReference.get() 是否返回 null 来区分死的映射和活的映射。但是这只是防止 Map 的内存消耗在应用程序的生命周期中不断增加所需要做的工作的一半,还需要做一些工作以便在键对象被收集后从 Map 中删除死项。否则,Map 会充满对应于死键的项。虽然这对于应用程序是不可见的,但是它仍然会造成应用程序耗尽内存。
引用队列是垃圾收集器向应用程序返回关于对象生命周期的信息的主要方法。弱引用有个构造函数取引用队列作为参数。如果用关联的引用队列创建弱引用,在弱引用对象成为 GC 候选对象时,这个引用对象就在引用清除后加入到引用队列中(具体参考上文软引用示例)。
WeakHashMap 有一个名为 expungeStaleEntries() 的私有方法,大多数 Map 操作中会调用它,它去掉引用队列中所有失效的引用,并删除关联的映射。
5.UML:使用关联类指明特定形式的引用
关联类能够用来指明特定形式的引用,如弱(weak)、软(soft)或虚 (phantom)引用。
也可以如下的构造型方式。

别再手动连线了!用Tessent IJTAG的SIB和TDR,5分钟搞定复杂芯片的DFT网络分区 本文探讨了如何利用Tessent IJTAG的SIB(Segment Insertion Bit)和TDR(Test Data Register)技术,高效解决复杂芯片DFT网络分区问题。通过智能化的扫描链管理和声明式定义,显著降低连接复杂度,提升测试覆盖率和良率,适用于超大规模SoC设计。 阅读详情

相关推荐

亿图图示(edrawmax中文版) v10.1.7pjb

edrawmax中文名叫做亿图图示,是一款非常棒的综合图形图表设计软件,既能实现流程图、架构图、工程图、思维导图等数百种专业领域图形图表的绘制,又能提供一个白板进行头脑风暴和任意编排,轻松实现数据和创意的可视化呈现。软件支持Windows、Mac、Linux及网络版,一端创作,多端同步,从而为跨端办公绘图提供新的解决方案,还兼容常用文档类的办公软件格式,包括图片、Office、PDF、Visio、Html、SVG等,尽可能的在文件格式这块满足用户多方面需求。软件支持创建260多种图表类型,拥有超过12500

qq_43293214的博客 1万+

从零搭建若依环境(非分离版)

若依是一个企业级快速开发平台,基于经典技术组合(Spring Boot、Spring Security、MyBatis、Jwt、Vue)。我学习时间也不长,做个简单的入门介绍,希望能帮助到刚接触若依的小伙伴。

zavier的乌托邦 3578

uds协议之can总线程序升级

uds协议简介 如何利用uds协议升级 升级流程 uds服务类型介绍

fangye945a的博客 1万+

什么是java对象的强、软、弱和虚引用

本文介绍对象的强、软、弱和虚引用的概念、应用及其在UML中的表示。1.对象的强、软、弱和虚引用   在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、

liaomin416100569的专栏 1129

DCA决策曲线的解读和代码实现

0.决策曲线 决策曲线分析法(Decision Curve Analysis,DCA)是个与ROC曲线相提并论的相对比较新的模型评价方法。 关于它的原理,长篇大论的医学统计学知识解读实在不是我的强项,放上两个链接偷偷懒: https://www.plob.org/article/12455.html https://www.iikx.com/news/statistics/1622.html 如果想看文章,这篇里的fig7就是:https://www.ncbi.nlm.nih.gov/pmc/artic

weixin_42960896的博客 1万+

从特斯拉到蔚来:拆解主流智能汽车的车联网架构,看它们如何实现‘车、路、云’协同

本文深度解析了特斯拉、蔚来等主流智能汽车的车联网架构,详细拆解了其‘车、路、云’协同的技术实现。从车内网络、车际通信到云端协同,分析了通信技术、系统架构等关键技术选择,揭示了不同厂商如何通过差异化布局构建竞争优势。

weixin_42525289的博客 580

UML类图六种箭头的含义

uml类图的箭头含义

Jrquen的博客 2974

Qt + windows + Linux+QtInstallerFramework打包教程

本文介绍了使用Qt Installer Framework在Windows和Linux系统下打包Qt应用程序的完整教程。Windows部分详细说明了从下载安装框架、配置环境变量、生成release版本,到创建安装包目录结构和修改配置文件的完整流程。Linux部分则重点讲解了环境变量设置、桌面应用配置(.desktop文件)以及两种打包方案:一种使用linuxdeployqt生成AppImage文件,另一种采用类似Windows的安装包方式。教程提供了关键配置文件(config.xml、package.xml

Qt历险记,专注Qt技术,三年医疗设备研发经验,1年机器视觉研发经验,半年柔性传感研发经验。 516

若依开源框架解析

1、框架介绍 RuoYi是一个基于Java技术开发的后台管理系统,目前官方同步在维护的有3个版本。 开源协议:MIT 解释:MIT是和BSD一样宽松的许可协议,作者只想保留版权,而无任何其他了限制.也就是说,你必须在你的发行版里包含原许可协议的声明,无论你是以二进制发布的还是以源代码发布的。 (1)若依不分离版本 RuoYi是基于经典技术组合(Spring Boot、ApacheShiro、MyBatis、Thymeleaf)主要目的让开发者......

Java后端技术栈 7万+

基于Matlab使用雷达资源管理有效跟踪多个机动目标仿真(附源码)

多功能雷达可以搜索目标,确认新轨道,并重新访问轨道以更新状态。为了执行这些功能,多功能雷达通常由资源管理器管理,该资源管理器创建用于搜索、确认和跟踪的雷达任务。这些任务是根据优先级和时间安排的,因此,在每个时间步长中,多功能雷达都可以将其波束指向所需的方向。在此示例中,对于用于跟踪机动目标的雷达,有两个相互冲突的要求:目标的数量及其初始位置通常事先不知道。因此,雷达必须不断搜索感兴趣的区域才能找到目标。此外,雷达需要在进入雷达覆盖区域后立即检测并建立对每个目标的跟踪。目标机动的时间段事先是未知的。

珞瑜的博客 3146

大疆前端开发面试题及参考答案(4万字长文)

在前端项目中,难点和性能优化的挑战无处不在。比如在处理复杂交互界面时,实现流畅的动画效果和实时反馈就是一大难点。当界面中有大量元素需要同时进行交互和动态更新,像电商平台的商品筛选和排序功能,不仅要保证操作的即时响应,还要确保界面在各种设备和网络环境下的稳定性,这就需要对事件处理、DOM 操作和数据更新机制有深入理解。在性能优化方面,首屏加载速度是常见的难点。当页面包含大量图片、脚本和样式文件时,如何合理地进行资源压缩、合并与缓存,以减少加载时间,是需要精心考虑的。

大模型大数据攻城狮的专栏 1155

Java:Java对象的强、软、弱和虚引用

1.Java对象的强、软、弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。这 就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走。一般说来,如果物品已经被扔到垃圾箱,想再 把它捡回来使用就不可能了。      但

2441

自动化上位机开发C#100例:如何用面向对象的方式封装雷赛运动控制卡EtherCAT总线卡(C#代码)

自动化上位机开发C#100例:雷赛运动控制卡EtherCAT总线卡C#封装类。

十多年IT经验,专注机器视觉,智能制造半导体行业 5031

Java学习——Java:对象的强、软、弱和虚引用

本文介绍对象的强、软、弱和虚引用的概念、应用及其在UML中的表示。   1.对象的强、软、弱和虚引用 在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、

编程进化论 1037

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

下一篇: linux下tar.gz、tar、bz2、zip等解压缩、压缩命令小结
guoping2018
博客等级 码龄16年 6粉丝 4原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值