在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(reachable)状态,程序才能使用它。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。在java.lang.ref包中提供了几个类:SoftReference类、WeakReference类和PhantomReference类,它们分别代表软引用、弱引用和虚引用。ReferenceQueue类表示引用队列,它可以和这三种引用类联合使用,以便跟踪Java虚拟机回收所引用的对象的活动。图1为对象应用类层次。
强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
弱引用(WeakReference)
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
对象可及性的判断
在很多时候,一个对象并不是从根集直接引用的,而是一个对象被其他对象引用,甚至同时被几个对象所引用,从而构成一个以根集为顶的树形结构。如图所示,在这个树形的引用链中,箭头的方向代表了引用的方向,所指向的对象是被引用对象。由图可以看出,从根集到一个对象可以由很多条路径。比如到达对象5的路径就有①-⑤,③-⑦两条路径。由此带来了一个问题,那就是某个对象的可及性如何判断:
单条引用路径可及性判断:在这条路径中,最弱的一个引用决定对象的可及性。
多条引用路径可及性判断:几条路径中,最强的一条的引用决定对象的可及性。
比如,我们假设图2中引用①和③为强引用,⑤为软引用,⑦为弱引用,对于对象5按照这两个判断原则,路径①-⑤取最弱的引用⑤,因此该路径对对象5的引用为软引用。同样,③-⑦为弱引用。在这两条路径之间取最强的引用,于是对象5是一个软可及对象。
在Android应用的开发中,为了防止内存溢出,在处理一些占用内存大而且声明周期较长的对象时候,可以尽量应用软引用和弱引用技术。虚引用主要用来跟踪对象被垃圾回收器回收的活动。
虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。只具有弱引用的对象拥有更短暂的生命周期,可能随时被回收。而只具有软引用的对象只有当内存不够的时候才被回收,在内存足够的时候,通常不被回收。
到底什么时候使用软引用,什么时候使用弱引用呢?个人认为,如果只是想避免OutOfMemory异常的发生,则可以使用软引用。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。还有就是可以根据对象是否经常使用来判断。如果该对象可能会经常使用的,就尽量用软引用。如果该对象不被使用的可能性更大些,就可以用弱引用。另外,和弱引用功能类似的是WeakHashMap。WeakHashMap对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收以后,其条目从映射中有效地移除。WeakHashMap使用ReferenceQueue实现的这种机制。
例如,我们看一个雇员信息查询系统的实例。我们将使用一个Java语言实现的雇员信息查询系统查询存储在磁盘文件或者数据库中的雇员人事档案信息。作为一个用户,我们完全有可能需要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息(同样,我们在浏览WEB页面的时候也经常会使用“后退”按钮)。这时我们通常会有两种程序实现方式:一种是把过去查看过的雇员信息保存在内存中,每一个存储了雇员档案信息的Java对象的生命周期贯穿整个应用程序始终;另一种是当用户开始查看其他雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的Java对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该雇员的档案信息的时候,重新构建该雇员的信息。很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。我们知道,访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度。
如何使用软引用:
SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。
看下面代码:
MyObject aRef = new MyObject(); SoftReference aSoftRef=new SoftReference(aRef);
此时,对于这个MyObject对象,有两个引用路径,一个是来自SoftReference对象的软引用,一个来自变量aReference的强引用,所以这个MyObject对象是强可及对象。
随即,我们可以结束aReference对这个MyObject实例的强引用:
aRef = null;
此后,这个MyObject对象成为了软可及对象。如果垃圾收集线程进行内存垃圾收集,并不会因为有一个SoftReference对该对象的引用而始终保留该对象。Java虚拟机的垃圾收集线程对软可及对象和其他一般Java对象进行了区别对待:软可及对象的清理是由垃圾收集线程根据其特定算法按照内存需求决定的。也就是说,垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软可反对象会被虚拟机尽可能保留。在回收这些对象之前,我们可以通过:
MyObject anotherRef=(MyObject)aSoftRef.get();
重新获得对该实例的强引用。而回收之后,调用get()方法就只能得到null了。
使用ReferenceQueue清除失去了软引用对象的SoftReference:
作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,如:
ReferenceQueue queue = new ReferenceQueue(); SoftReference ref=new SoftReference(aMyObject, queue);
那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉。常用的方式为:
SoftReference ref = null; while ((ref = (EmployeeRef) q.poll()) != null) { // 清除ref }
理解了ReferenceQueue的工作机制之后,我们就可以开始构造一个Java对象的高速缓存器了。关于软、弱引用的实例请参考相关实例文章。
相关推荐
本文将深入探讨四种引用类型:强引用、软引用、弱引用和虚引用。 首先,我们来理解强引用(Strong Reference)。强引用是最常见的引用类型,它代表了程序中的普通对象引用。当一个对象被强引用指向时,该对象被认为...
软引用是Java内存管理中的一种特性,它是一种弱于强引用但强于虚引用的引用类型。当系统内存充足时,即使对象只有软引用,垃圾回收器也不会回收这些对象。然而,当系统内存不足时,垃圾回收器会清除那些只被软引用的...
相比于强引用,软引用提供了更灵活的内存管理策略。在图片缓存中,使用软引用可以保证在系统内存紧张时,优先释放图片资源,降低内存溢出的风险。 三、BitmapCache类解析 在提供的`BitmapCache`类中,我们可以看到...
2. 软引用是弱于强引用的,垃圾回收器在内存不足时才会回收软引用的对象。 3. 软引用的对象可以被程序正常访问和使用,但需要通过软引用对象间接访问。 4. 软引用适合用来做内存敏感的高速缓存。 在使用软引用时...
本文介绍了强clean一般环的概念并将一些基本的结果推广到这个更广的环类。证明了强 clean一般环的角落环和强π一正则一般环都是强clean的,还讨论了强clean一般环的扩张并且证明了满足条件J(I)=Q(I)的交换clean一般环...
强Bazilevie函数族是复分析中的一个概念,它是一种特定的解析函数类。在这篇论文中,作者引入了强Bazilevie函数族的一个扩展Aα(卢),并对其进行了研究。这涉及到函数的从属关系、Fekete-Szegö不等式及其相关问题。...
弱电解质不同于强电解质,后者在溶液中几乎完全离解。弱电解质的电离通常是一个可逆过程,达到动态平衡,即电离平衡。 电离平衡是当弱电解质分子电离成离子和离子再结合成分子的速率相等时的状态,这种平衡遵循化学...
在本文中,我们开发了一种新的计算三点函数的新方法,该... 另外,应用于强耦合分析的新分析论据导致积分轮廓的修改,产生的结果与最近的六角形自举法一致。 这种修改还使Frolov-Tseytlin极限与弱耦合形式完全吻合。
相较于强人工智能,弱AI在功能上局限于完成特定任务,并不具备真正的自我意识或自主学习能力,即它们不能像人类一样理解所执行的任务。 在著作权领域,弱人工智能的发展产生了所谓的“人工智能作品”,即AI创作的...
这种方法相较于强耦合算法,在工程应用方面降低了对计算机性能的要求,并且降低了成本。 在起落架系统的研究背景下,飞机起落架在工作时会产生大量的热量,如果不进行有效的控制和散热,将会导致起落架舱内温度过高...
弱上拉电阻相比于强上拉电阻具有较小的电流驱动能力,通常用于防止信号线处于高阻态,保证逻辑清晰。 在Quartus II中设置管脚弱上拉电阻的步骤如下: 1. 打开Quartus II软件并进入项目工程。首先,确保你的设计...
3. **类型细分不明显**:相较于强类型语言,JavaScript中的数据类型划分较为宽松,例如数字类型并不区分整型和浮点型。 **JavaScript的运行环境包括:** - **浏览器**:这是JavaScript最初的应用领域,主要用于...
在电子行业中,电场强度传感器是一种至关重要的设备,尤其在涉及高压电力系统、电磁兼容测试、天线设计以及环境电磁污染监测等领域。本文件“行业分类-电子政务-一种可工作于强电场环境下的电场强度传感器.pdf”提供...
3. 关于强、弱电解质和非电解质的判断,例如乙酸(CH3COOH)是弱电解质,因为其在水中只部分离解;而氨气(NH3)溶于水虽然能导电,但氨本身是非电解质,氨与水反应生成的一水合氨(NH4OH)才是电解质。 4. 电解质溶液的...
4. weak引用:不同于强引用,weak引用不增加对象的引用计数。当对象的引用计数变为0时,即使有weak引用,对象也会被释放,而weak引用会自动置为nil,避免了内存泄漏。 三、运行时系统 Objective-C的动态性得益于其...
本文的研究聚焦于强音节和弱音节在发音过程中,嘴唇和舌头的空间共变现象。在这项研究中,研究者们通过对母语为汉语的受试者在发音时的嘴唇和舌头动作进行观察,探讨了它们之间的协调机制,以及在强调语句中强音节和...
本文的结果与这两个定理相结合,肯定了Ordentlich-Polyanskiy-Shayevitz关于强小集合扩张的猜想(2019年)以及Polyanskiy关于强Brascamp-Lieb不等式的猜想(2016年)。 证明方法基于一个函数的凸性和其拉格朗日对偶...
尽管醋酸在水中能够电离,但电离程度不高,因此它属于弱电解质,不同于强电解质如高锰酸钾或硫酸钡,它们在水中完全电离。 在【加固训练】部分,题目的重点在于区分电解质、非电解质和弱电解质。例如,CO2的水溶液...
暴露于强 ELF 磁场不会改变心脏自主控制机制 Bioelectromagnetics 21:413^421 (2000) 暴露于强 ELF 磁场不会改变心脏自主控制机制 Charles Graham,1* Antonio Sastre,1 Mary R. Cook,1 Robert Kavet,2 Mary M. ...