转载自:http://www.javaeye.com/topic/401478

Java 中一共有 4 种类型的引用 : StrongReference、 SoftReference、 WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵),
这 4 种类型的引用与 GC 有着密切的关系, 让我们逐一来看它们的定义和使用场景 :

1. Strong Reference

StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收

Java代码
  1. @Test
  2. publicvoidstrongReference(){
  3. Objectreferent=newObject();
  4. /**
  5. *通过赋值创建StrongReference
  6. */
  7. ObjectstrongReference=referent;
  8. assertSame(referent,strongReference);
  9. referent=null;
  10. System.gc();
  11. /**
  12. *StrongReference在GC后不会被回收
  13. */
  14. assertNotNull(strongReference);
  15. }

2. WeakReference & WeakHashMap

WeakReference, 顾名思义, 是一个弱引用, 当所引用的对象在 JVM 内不再有强引用时, GC 后 weak reference 将会被自动回收

Java代码
  1. @Test
  2. publicvoidweakReference(){
  3. Objectreferent=newObject();
  4. WeakReference<Object>weakRerference=newWeakReference<Object>(referent);
  5. assertSame(referent,weakRerference.get());
  6. referent=null;
  7. System.gc();
  8. /**
  9. *一旦没有指向referent的强引用,weakreference在GC后会被自动回收
  10. */
  11. assertNull(weakRerference.get());
  12. }

WeakHashMap 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry

Java代码
  1. @Test
  2. publicvoidweakHashMap()throwsInterruptedException{
  3. Map<Object,Object>weakHashMap=newWeakHashMap<Object,Object>();
  4. Objectkey=newObject();
  5. Objectvalue=newObject();
  6. weakHashMap.put(key,value);
  7. assertTrue(weakHashMap.containsValue(value));
  8. key=null;
  9. System.gc();
  10. /**
  11. *等待无效entries进入ReferenceQueue以便下一次调用getTable时被清理
  12. */
  13. Thread.sleep(1000);
  14. /**
  15. *一旦没有指向key的强引用,WeakHashMap在GC后将自动删除相关的entry
  16. */
  17. assertFalse(weakHashMap.containsValue(value));
  18. }

3. SoftReference

SoftReference 于 WeakReference 的特性基本一致, 最大的区别在于 SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存应用

Java代码
  1. @Test
  2. publicvoidsoftReference(){
  3. Objectreferent=newObject();
  4. SoftReference<Object>softRerference=newSoftReference<Object>(referent);
  5. assertNotNull(softRerference.get());
  6. referent=null;
  7. System.gc();
  8. /**
  9. *softreferences只有在jvmOutOfMemory之前才会被回收,所以它非常适合缓存应用
  10. */
  11. assertNotNull(softRerference.get());
  12. }

4. PhantomReference

作为本文主角, Phantom Reference(幽灵引用) 与 WeakReference 和 SoftReference 有很大的不同, 因为它的 get() 方法永远返回 null, 这也正是它名字的由来

Java代码
  1. @Test
  2. publicvoidphantomReferenceAlwaysNull(){
  3. Objectreferent=newObject();
  4. PhantomReference<Object>phantomReference=newPhantomReference<Object>(referent,newReferenceQueue<Object>());
  5. /**
  6. *phantomreference的get方法永远返回null
  7. */
  8. assertNull(phantomReference.get());
  9. }

诸位可能要问, 一个永远返回 null 的 reference 要来何用, 请注意构造 PhantomReference 时的第二个参数 ReferenceQueue(事实上 WeakReference & SoftReference 也可以有这个参数),
PhantomReference 唯一的用处就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中.

5. RererenceQueue

当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作. 将一个 ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个对象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的 entries.

Java代码
  1. @Test
  2. publicvoidreferenceQueue()throwsInterruptedException{
  3. Objectreferent=newObject();
  4. ReferenceQueue<Object>referenceQueue=newReferenceQueue<Object>();
  5. WeakReference<Object>weakReference=newWeakReference<Object>(referent,referenceQueue);
  6. assertFalse(weakReference.isEnqueued());
  7. Reference<?extendsObject>polled=referenceQueue.poll();
  8. assertNull(polled);
  9. referent=null;
  10. System.gc();
  11. assertTrue(weakReference.isEnqueued());
  12. Reference<?extendsObject>removed=referenceQueue.remove();
  13. assertNotNull(removed);
  14. }

6. PhantomReference vs WeakReference

PhantomReference 有两个好处, 其一, 它可以让我们准确地知道对象何时被从内存中删除, 这个特性可以被用于一些特殊的需求中(例如 Distributed GC, XWork 和 google-guice 中也使用 PhantomReference 做了一些清理性工作).

其二, 它可以避免 finalization 带来的一些根本性问题, 上文提到 PhantomReference 的唯一作用就是跟踪 referent 何时被 enqueue 到 ReferenceQueue 中, 但是 WeakReference 也有对应的功能, 两者的区别到底在哪呢 ?
这就要说到 Object 的 finalize 方法, 此方法将在 gc 执行前被调用, 如果某个对象重载了 finalize 方法并故意在方法内创建本身的强引用, 这将导致这一轮的 GC 无法回收这个对象并有可能
引起任意次 GC, 最后的结果就是明明 JVM 内有很多 Garbage 却 OutOfMemory, 使用 PhantomReference 就可以避免这个问题, 因为 PhantomReference 是在 finalize 方法执行后回收的,也就意味着此时已经不可能拿到原来的引用, 也就不会出现上述问题, 当然这是一个很极端的例子, 一般不会出现.

7. 对比

taken fromhttp://mindprod.com/jgloss/phantom.html

Soft vs Weak vs Phantom References
Type Purpose Use When GCed Implementing Class
Strong Reference An ordinary reference. Keeps objects alive as long as they are referenced. normal reference. Any object not pointed to can be reclaimed. default
Soft Reference Keeps objects alive provided there’s enough memory. to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key. After a first gc pass, the JVM decides it still needs to reclaim more space. java.lang.ref.SoftReference
Weak Reference Keeps objects alive only while they’re in use (reachable) by clients. Containers that automatically delete objects no longer in use. After gc determines the object is only weakly reachable java.lang.ref.WeakReference
java.util.WeakHashMap
Phantom Reference Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use offinalize()) Special clean up processing After finalization. java.lang.ref.PhantomReference

8. 小结
一般的应用程序不会涉及到 Reference 编程, 但是了解这些知识会对理解 GC 的工作原理以及性能调优有一定帮助, 在实现一些基础性设施比如缓存时也可能会用到, 希望本文能有所帮助.

理解 Java 的 GC 与 幽灵引用相关推荐

  1. java 幽灵引用_全面解析Java中的GC与幽灵引用

    Java 中一共有 4 种类型的引用 : StrongReference. SoftReference. WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵) ...

  2. 深入理解 Java 之 GC 到底如何工作

     当程序创建对象,数组等引用类型实体时,系统都会在堆内存中为之分配一块内存区,对象就保存在这块内存区,当这块内存不再被任何变量引用时,这块内存就变成垃圾,系统就要回收. 只回收堆内存中对象,不会回 ...

  3. 理解Java自定义类作为数据类型——引用数据类型

    目录 说在前面的话 复现问题 引用数据类型的理解 总结 说在前面的话 前言:Java的数据类型按照类型可分为基本数据类型(byte.short.int.long.double.float.char.b ...

  4. java 准备 解析_深入理解JAVA虚拟机学习笔记24——类加载的准备和解析

    每天进步一点点! 今天我们一起看一下类加载的准备阶段和解析阶段. 先看一下准备阶段:主要任务是在方法区中为类变量(仅static修饰变量,不包含实例变量)分配内存并设置类变量初始化的阶段. 这里面的区 ...

  5. 《深入理解java虚拟机》学习笔记四/垃圾收集器GC学习/一

    Grabage Collection      GC GC要完毕的三件事情: 哪些内存须要回收? 什么时候回收? 怎样回收? 内存运行时区域的各个部分中: 程序计数器.虚拟机栈.本地方法栈这3个区域随 ...

  6. 《深入理解java虚拟机》笔记2——GC算法与内存分配策略

    说起垃圾收集(Garbage Collection, GC),想必大家都不陌生,它是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如Sca ...

  7. 深入理解JVM03--判断对象是否存活(引用计数算法、可达性分析算法,最终判定),Eclipse设置GC日志输出,引用

    本文是基于周志明的<深入理解Java虚拟机> 堆中几乎存放着Java世界中所有的对象实例,垃圾收集器在对堆回收之前,第一件事情就是要确定这些对象哪些还"存活"着,哪些对 ...

  8. 深入理解JVM(三)——JVM之判断对象是否存活(引用计数算法、可达性分析算法,最终判定),Eclipse设置GC日志输出,引用

    本文转载自https://blog.csdn.net/ochangwen/article/details/51406779 本文是基于周志明的<深入理解Java虚拟机> 堆中几乎存放着Ja ...

  9. 深入理解 Java 虚拟机 - 你了解 GC 算法原理吗

    来自:好好学Java 虚拟机系列文章 深入理解 Java 虚拟机(第一弹) - Java 内存区域透彻分析 深入理解 Java 虚拟机(第二弹) - 常用 vm 参数分析 深入理解 Java 虚拟机- ...

最新文章

  1. 2019最具特色的web前端技术分享
  2. python datetime.datetime 当前_python之time和datetime的常用方法
  3. 爬虫学习笔记(十三)—— scrapy-redis(二):存储到MySQL、Scrapy项目部署
  4. 走向AI摄影终极之路 AVA数据集后时代与发展?
  5. C51对标准C语言的扩展 / 数据类型
  6. golang map源码分析
  7. WordPress通过插件发送邮件
  8. Codeforces - 65D - Harry Potter and the Sorting Hat - 简单搜索
  9. spring boot 集合mysql_Spring boot整合mysql和druid
  10. windows服务器下com6僵尸***删除
  11. security工作笔记004---.NET Web安全性-身份验证和授权(一)之Principal
  12. 用DeflateStream和GZipStream压缩数据
  13. JAVA utf8编码字符_Java中的UTF-8字符编码
  14. Jupyter notebook 修复
  15. 二、建模及画网格软件推荐
  16. 如何卸载Adobe Creative Cloud
  17. qq机器人智能聊天插件源码
  18. 海思vo 分屏显示总结
  19. linux从源码编译cairo,如何在windows下编译cairo
  20. IOS相关培训机构课程内容汇总

热门文章

  1. 国际电联秘书长特别代表杨晓雅:2020年全球将接入500亿物联网终端
  2. 再见Windows C++
  3. Linux中进程正常退出return和exit()的区别
  4. linux lsattr命令: 显示文件属性
  5. Python学习记录——函数
  6. JavaScript设计模式之创建型设计模式
  7. 在Scala IDEA for Eclipse或IDEA里程序编译实现与在Spark Shell下的对比(其实就是那么一回事)...
  8. 关于python中的字符串编码理解
  9. spring整合shiro
  10. 灵活理解思科三层结构