Java 引用 WeakReference

Reference 是一个抽象类,而 SoftReference,WeakReference,PhantomReference 以及 FinalReference 都是继承它的具体类。
接下来我们来分别介绍和分析强引用以及 java.lang.ref 包下各种虚引用的特性及用法。
StrongReference, SoftReference, WeakReference 以及 PhantomReference 的特性及用法

StrongReference:

我们都知道 JVM 中对象是被分配在堆(heap)上的,当程序行动中不再有引用指向这个对象时,这个对象就可以被垃圾回收器所回收。这里所说的引用也就是我们一般意义上申明的对象类型的变量(如 String, Object, ArrayList 等),区别于原始数据类型的变量(如 int, short, long 等)也称为强引用。

在了解虚引用之前,我们一般都是使用强引用来对对象进行引用。如:

1. StrongReference usage

String tag = new String("T");  

此处的 tag 引用就称之为强引用。而强引用有以下特征:

    强引用可以直接访问目标对象。
    强引用所指向的对象在任何时候都不会被系统回收。
    强引用可能导致内存泄漏。

我们要讨论的这三种 Reference 较之于强引用而言都属于“弱引用”,也就是他们所引用的对象只要没有强引用,就会根据条件被 JVM 的垃圾回收器所回收,它们被回收的时机以及用法各不相同。下面分别来进行讨论。

SoftReference:

SoftReference 在“弱引用”中属于最强的引用。SoftReference 所指向的对象,当没有强引用指向它时,会在内存中停留一段的时间,垃圾回收器会根据 JVM 内存的使用情况(内存的紧缺程度)以及 SoftReference 的 get() 方法的调用情况来决定是否对其进行回收。(后面章节会用几个实验进行阐述)

具体使用一般是通过 SoftReference 的构造方法,将需要用弱引用来指向的对象包装起来。当需要使用的时候,调用 SoftReference 的 get() 方法来获取。当对象未被回收时 SoftReference 的 get() 方法会返回该对象的强引用。如下:

2. SoftReference usage

SoftReference<Bean> bean = new SoftReference<Bean>(new Bean("name", 10));
 System.out.println(bean.get());// “name:10”  

软引用有以下特征:

    软引用使用 get() 方法取得对象的强引用从而访问目标对象。
    软引用所指向的对象按照 JVM 的使用情况(Heap 内存是否临近阈值)来决定是否回收。
    软引用可以避免 Heap 内存不足所导致的异常。

当垃圾回收器决定对其回收时,会先清空它的 SoftReference,也就是说 SoftReference 的 get() 方法将会返回 null,然后再调用对象的 finalize() 方法,并在下一轮 GC 中对其真正进行回收。

WeakReference:

WeakReference 是弱于 SoftReference 的引用类型。弱引用的特性和基本与软引用相似,区别就在于弱引用所指向的对象只要进行系统垃圾回收,不管内存使用情况如何,永远对其进行回收(get() 方法返回 null)

完全可以通过和 SoftReference 一样的方式来操作 WeakReference,这里就不再复述。
弱引用有以下特征:

    弱引用使用 get() 方法取得对象的强引用从而访问目标对象。
    一旦系统内存回收,无论内存是否紧张,弱引用指向的对象都会被回收。
    弱引用也可以避免 Heap 内存不足所导致的异常。

PhantomReference:
PhantomReference 是所有“弱引用”中最弱的引用类型。不同于软引用和弱引用,虚引用无法通过 get() 方法来取得目标对象的强引用从而使用目标对象,观察源码可以发现 get() 被重写为永远返回 null。
那虚引用到底有什么作用?其实虚引用主要被用来 跟踪对象被垃圾回收的状态,通过查看引用队列中是否包含对象所对应的虚引用来判断它是否 即将被垃圾回收,从而采取行动。它并不被期待用来取得目标对象的引用,而目标对象被回收前,它的引用会被放入一个 ReferenceQueue 对象中,从而达到跟踪对象垃圾回收的作用。
所以具体用法和之前两个有所不同,它必须传入一个 ReferenceQueue 对象。当虚引用所引用对象被垃圾回收后,虚引用会被添加到这个队列中。如:

3. PhantomReference usage

public static void main(String[] args) {
 ReferenceQueue<String> refQueue = new ReferenceQueue<String>();
 PhantomReference<String> referent = new PhantomReference<String>(
     new String("T"), refQueue);
 System.out.println(referent.get());// null   

 System.gc();
 System.runFinalization();   

 System.out.println(refQueue.poll() == referent); //true
 }   

值得注意的是,对于引用回收方面,虚引用类似强引用不会自动根据内存情况自动对目标对象回收,Client 需要自己对其进行处理以防 Heap 内存不足异常。

虚引用有以下特征:

虚引用永远无法使用 get() 方法取得对象的强引用从而访问目标对象。
    虚引用所指向的对象在被系统内存回收前,虚引用自身会被放入 ReferenceQueue 对象中从而跟踪对象垃圾回收。
    虚引用不会根据内存情况自动回收目标对象。

另外值得注意的是,其实 SoftReference, WeakReference 以及 PhantomReference 的构造函数都可以接收一个 ReferenceQueue 对象。当 SoftReference 以及 WeakReference 被清空的同时,也就是 Java 垃圾回收器准备对它们所指向的对象进行回收时,调用对象的 finalize() 方法之前,它们自身会被加入到这个 ReferenceQueue 对象中,此时可以通过 ReferenceQueue 的 poll() 方法取到它们。而 PhantomReference 只有当 Java 垃圾回收器对其所指向的对象真正进行回收时,会将其加入到这个 ReferenceQueue 对象中,这样就可以追综对象的销毁情况。

让我们来回顾一下四种引用类型的表现以及在垃圾回收器回收清理内存时的表现 .

软引用 (SoftReference), 引用类型表现为当内存接近满负荷 , 或对象由 SoftReference.get() 方法的调用没有发生一段时间后 , 垃圾回收器将会清理该对象 . 在运行对象的 finalize 方法前 , 会将软引用对象加入 ReferenceQueue 中去 .
    弱引用 (WeakReference), 引用类型表现为当系统垃圾回收器开始回收时 , 则立即会回收该对象的引用 . 与软引用一样 , 弱引用也会在运行对象的 finalize 方法之前将弱引用对象加入 ReferenceQueue.
    强引用 (FinalReference), 这是最常用的引用类型 . JVM 系统采用 Finalizer 来管理每个强引用对象 , 并将其被标记要清理时加入 ReferenceQueue, 并逐一调用该对象的 finalize() 方法 .
    虚引用 (PhantomReference), 这是一个最虚幻的引用类型 . 无论是从哪里都无法再次返回被虚引用所引用的对象 . 虚引用在系统垃圾回收器开始回收对象时 , 将直接调用 finalize() 方法 , 但不会立即将其加入回收队列 . 只有在真正对象被 GC 清除时 , 才会将其加入 Reference 队列中去 .
当多次运行系统垃圾回收后,IBM JVM 将软引用一并加入了回收队列中,并运行了其 finalize 方法。另外,即使经过很多次系统垃圾回收,虚引用也没有被加入到队列中去。不知道这是不是 IBM JVM 的一个小小的 BUG 所在。 
    SoftReference 中 Oracle JVM 的表现满足规范,只当内存不足时才进行回收。而 IBM JVM 的策略则更为积极,在内存尚且充足的情况下也进行了回收,值得注意。
    PhantomReference 中 Oracle JVM 的表现满足规范,执行 finalize 后若干次 GC 就被添加到了 Queue 中。而 IBM JVM 则始终没有被添加到 Queue 中导致了死循环。所以在使用 PhantomReference 时出现类似的情况时,可以考虑是否是因为使用了不同 JVM 所导致。

时间: 2024-10-24 11:33:29

Java 引用 WeakReference的相关文章

Java引用总结--StrongReference、SoftReference、WeakReference、PhantomReference

http://www.cnblogs.com/skywang12345/p/3154474.html 1 Java引用介绍 Java从1.2版本开始引入了4种引用,这4种引用的级别由高到低依次为:    强引用  >  软引用  >  弱引用  >  虚引用 ⑴强引用(StrongReference)    强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回

关于Java引用,你必须知道这些

引用 Java 虚拟机接管了所有的内存分配与回收工作,极大地减少了程序员的工作量和错误率.GC 在回收内存时,通常采用被称为可达性分析的算法判断一个对象是否可以回收.而在可达性分析中,对象的引用有着决定性的作用.在下图中,GC 从 GC Roots 开始顺着引用链往下寻找对象,发现当前有引用的对象为object 1.object 2.object 3.object 4,而object 5.object 6.object 7虽然互相之间有引用但已经无法从外部引用到.因此,图中 object 1-4

4种Java引用浅解

近期研究Java Cache实现,发现使用到了软引用(SoftReference),不太理解,查阅了JDK文档.代码以及几篇文章.做个小结,如有错误,欢迎指正. 之所以想学习一下Java的几种引用类型,原因有两个: 理解Java Cache实现.学习Java引用与Java垃圾回收机制的关系 内存资源是有限的,须要合理的利用.Cache不是只HashMap那么简单,Java引用与Java垃圾回收机制也有很紧密的关系. 避免对Java引用的错误使用 某个同事把5000+交易数据放到一个HashMap

Java引用的种类

---恢复内容开始--- 距离第一篇貌似有很久了,md拖延症越来越严重了,不过每天十点多下班回家到家就十一点多了,就只想睡觉了.不瞎bb了,直接上干活.主要想记录一下关于java引用. 搞java的应该对引用这个词非常非常熟悉不过了,记得刚入门java的时候,这个词就一直伴随着我们.在java中又一个非常重要的东西那就是GC,对于gc来说,判断一个对象是否可回收的标志就在于该对象是不是还在被引用(关于gc下次专门记录一波),jvm为了更好的管理对象的引用,在lang.ref包下面有三个类:Sof

java SoftReference WeakReference

Java 2 平台引入了 java.lang.ref 包,其中包括的类可以让您引用对象,而不将它们留在内存中.这些类还提供了与垃圾收集器(garbage collector)之间有限的交互. 1.先“由强到弱”(只的是和垃圾回收器的关系)明确几个基本概念:      strong references是那种你通常建立的reference,这个reference就是强可及的.这个不会被垃圾回收器自动回收.例如:      StringBuffer buffer = new StringBuffer

浅解四种Java引用

最近研究Java Cache实现,发现使用到了软引用(SoftReference),不太理解,查阅了JDK文档.代码以及几篇文章.做个小结,如有错误,欢迎指正. 之所以想学习一下Java的几种引用类型,原因有两个: 理解Java Cache实现.学习Java引用与Java垃圾回收机制的关系 内存资源是有限的,需要合理的利用.Cache不是仅仅HashMap那么简单,Java引用与Java垃圾回收机制也有非常紧密的关系. 避免对Java引用的错误使用 某个同事把5000+交易数据放到一个HashM

JVM【第十二回】:【Java引用】

无论通过引用计数算法判断对象的引用数量,还是通过根搜索算法判断对象的引用链是否可达,判定对象是否存活都与"引用"有关.在JDK1.2之前,Java中的引用的定义很传统:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用.这种定义很纯粹,但是太过狭隘.我们希望能描述这样一类对象:当内存空间还足够时,则能保留在内存之中:如果内存在进行垃圾收集后还是非常紧张,则可以抛弃这些对象.很多系统的的缓存功能都符合这样的引用场景 在JDK1.2之后,

Java引用类型变量

Java引用类型变量 1.编译时类型:由声明该变量时使用的类型决定 2.执行时类型:由实际赋给该变量的对象决定    类型不一致的假设编译时类型和执行,可能会出现多态性 版权声明:本文博主原创文章.博客,未经同意不得转载.

Java引用变量的类型

Java引用变量的类型 1.编译时类型:由声明该变量时使用的类型决定 2.运行时类型:由实际赋给该变量的对象决定    如果编译时类型和运行时类型不一致,就可能出现多态性