`
liufei.fir
  • 浏览: 675863 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多
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 所导致。
分享到:
评论

相关推荐

    java8 探讨与分析匿名内部类、lambda表达式、方法引用的底层实现的测试用例

    这是原文中用到的测试用例,注意改一下包名。包括了test1~test4。

    JAVA垃圾回收机制

    垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机制并未改变。垃圾收集的目的在于清除不再...

    《Java 8 in Action》是一本关于 Java 编程语言的书籍,重点介绍了 Java 8 中引入的新特性和改进

    新的日期和时间 API: 探讨 Java 8 中新增的日期和时间 API,以及如何使用这些 API 来处理日期、时间和时区等相关操作。 并发编程改进: 讨论 Java 8 中对并发编程的改进,包括 CompletableFuture、新的并发工具和...

    探讨Java中函数是值传递还是引用传递问题

    主要介绍了探讨Java中函数是值传递还是引用传递问题,非常不错,具有参考借鉴价值,需要的朋友可以参考下

    详细介绍Java垃圾回收机制

    垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机制并未改变。垃圾收集的目的在于清除不再...

    JAVA基础课程讲义

    接口的本质探讨 84 接口使用要点 85 接口的多继承 86 面向接口编程 87 OOP更多应用 87 组合 87 内部类(innerclasses) 88 字符串(java.lang.String类)的使用 90 字符串相等的判断 92 思考作业 93 上机作业 94 第四...

    Java编程思想(完整版)

    在本章,我们将探讨Java程序的基本组件,并体会为什么说Java乃至Java程序内的一切都是对象。 2.1 用句柄操纵对象 2.2 必须创建所有对象: 创建句柄时,我们希望它同一个新对象连接。通常用new关键字达到这一目的。...

    Java零基础-参数传递-2.md

    读者将学习Java中方法调用时的参数传递方式,并重点探讨基本类型和引用类型在参数传递过程中的特点和区别。此外,我们还将介绍可变参数和返回值的使用方法。 能学到什么: 学习Java中方法调用时的参数传递方式。 ...

    操作系统实验-CPU-进程-调度-内存分配-java

    第二期为结合别人代码,对本人菜鸟级作品的评估和对java项目开发的进一步探讨; 2,因为资源中会引用他人的作品,涉及原创的问题,故在“操作系统实验项目开发声明.txt”中予以声明, 3,因个人时间安排原因,暂上传...

    Sun公司提供的Java连接SQL Server的方法(超简单),不需要引用连接数据库的jar包

    Sun公司提供的Java连接SQL Server的方法(超简单),不需要引用连接数据库的jar包,非常方便!值得探讨!

    值类型和引用类型的区别

    言归正传,咱还是先来探讨探讨这二者之间有什么区别吧。记得有一次电话面试中,我直接跟面试官说:“值类型是现金, 引用类型是存折”,后来想想当时说这话虽是有点儿冲动地脱口而出,但也没什么不妥。我这人不善于...

    java深入理解浅拷贝和深拷贝

    java中存在两种类型,基础类型和引用类型。 java的赋值都是传值的,对于基础类型来说,会拷贝具体的内容,但是对于引用对象来说,存储的这个值只是指向实际对象的地址,拷贝也只会拷贝引用地址。 因为引用对象的存在...

    Java虚拟机

    第五部分探讨了Java实现高效并发的原理,包括JVM内存模型的结构和操作;原子性、可见性和有序性在Java内存模型中的体现;先行发生原则的规则和使用;线程在Java语言中的实现原理;虚拟机实现高效并发所做的一系列锁...

    Java 中几种获取文件路径的方式

    在 Java 代码中以当前运行的代码所在的位置为参照位置,只要被引用的文件相对于引用的文件的位置不变就可以被读取到。一旦改变相对位置就无法被读取到。 2.2 绝对路径 文件在文件系统中真正存在的路径,是指从硬盘的...

    Java 理论与实践:用弱引用堵住内存泄漏

    本月,负责保障应用程序健康的工程师 Brian Goetz 探讨了无意识的对象保留的常见原因,并展示了如何用弱引用堵住泄漏。  要让垃圾收集(GC)回收程序不再使用的对象,对象的逻辑 生命周期(应用程序使用它的时间...

    Java中的对象数组

    java中数据类型的存储分为两大类,基本数据类型(也称为原始数据类型)和引用数据类型(也称为复合类型)。数组是引用数据类型中的一种。它是引用数据类型、基本数据类型的数组,在存储时也是同引用数据类型类似,...

    java及C++中传值传递、引用传递和指针方式的理解

    为什么 Java 只有值传递,但 C++ 既有值传递,又有引用传递呢?今天我们就来探讨下这个问题,有需要的朋友可以参考下

    《Java项目开发》课程的法制教育探析.pdf

    本文结合作者个人教学经验,对《java语言程序设计》教学过程中学生不太容易掌握的引用数据类型进行了分析和探讨,得出了一些有益的教学经验,并取得了不错的教学效果。

    Ajax安全技术

    , 《AJAX安全技术》一书对AJAX安全这一未开发领域进行了非常严谨、彻底的探讨。每个AJAX工程师都应该去掌握《AJAX安全技术》中的知识——至少应该明白其中的原理。, 《AJAX安全技术》适合广大基于AJAX开发Web程序的...

    concurrent 多线程 教材

    12 Java单例对象同步问题探讨 13 Java 理论与实践: 描绘线程安全性 (2) 14 编写高效的线程安全类 (2) 15 轻松使用线程 同步不是敌人.mht 16 轻松使用线程 减少争用.mht 17 轻松使用线程 不共享有时是最好的.mht...

Global site tag (gtag.js) - Google Analytics