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

这 4 种类型的引用与 GC 有着密切的关系,  让我们逐一来看它们的定义和使用场景 :

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

Java代码

@Test

public void strongReference() {

Object referent = new Object();

/**

* 通过赋值创建 StrongReference

*/

Object strongReference = referent;

assertSame(referent, strongReference);

referent = null;

System.gc();

/**

* StrongReference 在 GC 后不会被回收

*/

assertNotNull(strongReference);

}

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

@Test

public void weakReference() {

Object referent = new Object();

WeakReference weakRerference = new WeakReference(referent);

assertSame(referent, weakRerference.get());

referent = null;

System.gc();

/**

* 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收

*/

assertNull(weakRerference.get());

}

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

@Test

public void weakHashMap() throws InterruptedException {

Map weakHashMap = new WeakHashMap();

Object key = new Object();

Object value = new Object();

weakHashMap.put(key, value);

assertTrue(weakHashMap.containsValue(value));

key = null;

System.gc();

/**

* 等待无效 entries 进入 ReferenceQueue 以便下一次调用 getTable 时被清理

*/

Thread.sleep(1000);

/**

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

*/

assertFalse(weakHashMap.containsValue(value));

}

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

@Test

public void softReference() {

Object referent = new Object();

SoftReference softRerference = new SoftReference(referent);

assertNotNull(softRerference.get());

referent = null;

System.gc();

/**

*  soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用

*/

assertNotNull(softRerference.get());

}

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

Java代码

@Test

public void phantomReferenceAlwaysNull() {

Object referent = new Object();

PhantomReference phantomReference = new PhantomReference(referent, new ReferenceQueue());

/**

* phantom reference 的 get 方法永远返回 null

*/

assertNull(phantomReference.get());

}

诸位可能要问, 一个永远返回 null 的 reference 要来何用,  请注意构造 PhantomReference 时的第二个参数 ReferenceQueue(事实上 WeakReference & SoftReference 也可以有这个参数),

PhantomReference 唯一的用处就是跟踪 referent  何时被 enqueue 到 ReferenceQueue 中.

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

Java代码

@Test

public void referenceQueue() throws InterruptedException {

Object referent = new Object();

ReferenceQueue referenceQueue = new ReferenceQueue();

WeakReference weakReference = new WeakReference(referent, referenceQueue);

assertFalse(weakReference.isEnqueued());

Reference extends Object> polled = referenceQueue.poll();

assertNull(polled);

referent = null;

System.gc();

assertTrue(weakReference.isEnqueued());

Reference extends Object> removed = referenceQueue.remove();

assertNotNull(removed);

}

6、PhantomReference  vs WeakReferencePhantomReference  有两个好处, 其一, 它可以让我们准确地知道对象何时被从内存中删除, 这个特性可以被用于一些特殊的需求中(例如 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、 对比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 幽灵引用_全面解析Java中的GC与幽灵引用相关推荐

  1. java斗地主代码_实例解析java如何实现斗地主代码

    实例解析java如何实现斗地主代码 发布时间:2020-07-20 14:41:41 来源:亿速云 阅读:73 作者:小猪 小编这次要给大家分享的是实例解析java如何实现斗地主代码,文章内容丰富,感 ...

  2. java 编码解码_深入解析Java中的编码转换以及编码和解码操作

    一.Java编码转换过程 我们总是用一个java类文件和用户进行最直接的交互(输入.输出),这些交互内容包含的文字可能会包含中文.无论这些java类是与数据库交互,还是与前端页面交互,他们的生命周期总 ...

  3. java monitor 用法_[作业解析]并发中的Monitor及在Java中的运用如notify(),synchronized等用法...

    作业题目: 给定一个如下Java类Konto(即银行帐号),能实现存钱einzahlen和取钱auszahlen的功能. /* Eine Klasse für Bankkonten, die noch ...

  4. java 字节 操作_实例解析Java byte数组操纵方式代码

    字节数组的关键在于它为存储在该部分内存中的每个8位值提供索引(快速),精确的原始访问,并且您可以对这些字节进行操作以控制每个位. 坏处是计算机只将每个条目视为一个独立的8位数 - 这可能是你的程序正在 ...

  5. java 内存排序_详细解析Java内存,处理器重排序,编译器重排序以及它对线程的影响...

    欢迎大家搜索"小猴子的技术笔记"关注我的公众号,有问题可以及时和我交流. 我们在编写程序的时候有一个编写代码的顺序,那么计算机执行的时候就是按照我们编写代码的顺序来执行的吗?答案是 ...

  6. java的弱引用_深入理解Java中的弱引用

    不久之前,我面试了一些求职Java高级开发工程师的应聘者.我常常会面试他们说,"你能给我介绍一些Java中得弱引用吗?",如果面试者这样说,"嗯,是不是垃圾回收有关的?& ...

  7. java 参数类型不确定_详细解析Java虚拟机的栈帧结构

    什么是栈帧? 正如大家所了解的,Java虚拟机的内存区域被划分为程序计数器.虚拟机栈.本地方法栈.堆和方法区.(什么?你还不知道,赶紧去看看<Java虚拟机内存结构及编码实战>)这次要介绍 ...

  8. java 字符串乱码_这份Java面试题含答案解析竟然真的让你不用在面试上“如履薄冰”...

    面试题集共分为以下十部分: 一.Core Java: 1 - 95 题1 - 24 页 基础及语法: 1 - 61 题1 - 13 页 异常: 62 - 69 题13 - 15 页 集合: 70 - ...

  9. java虚引用_深入了解JAVA 虚引用

    定义 虚引用是使用PhantomReference创建的引用,虚引用也称为幽灵引用或者幻影引用,是所有引用类型中最弱的一个.一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用获 ...

最新文章

  1. 【Python金融量化 1- 100 】三、流行股票指数
  2. 在Android Studio进行“简单配置”单元测试(Android Junit)
  3. 程序编写经验教训_编写您永远都不会忘记的有效绩效评估的经验教训。
  4. 用计算机解决问题听课笔记,《计算机解决问题的过程》的教学设计
  5. 自己动手清除电脑中的***程序
  6. 转载--ASP解决AJAX带来的码问题
  7. python图像锐化滤波_Laplacian滤波器实现并用于图像锐化
  8. WEB前端缓存解决方案
  9. 易飞erp系统服务器怎么启动,如何使用易飞ERP系统
  10. RHEL7的DNS服务
  11. 微信小程序:装B神器P图修改微信流量主小程序源码下载趣味恶搞图制作免服务器域名
  12. RNA m6A修饰问题汇总(第二期)
  13. 人工智能与高性能计算
  14. 【数字图像处理】模拟Matlab的imresize()写一个你自己的imresize()函数,至少应实现‘nearest’和‘bilinear’两种方法
  15. 小米3刷android 6.0,小米3/4/Note适配Android6.0刷机包链接 注意事项及提取密匙
  16. 计算机组装走线,DIY电脑装机教程 走背线方法图文教程
  17. boss直聘__zp_stoken__逆向分析2021.10版
  18. 大数据分析Python和R语言的优缺点
  19. TCP头部分析与确认号的理解
  20. Html 视频分屏显示[转]

热门文章

  1. Linux下Makefile的automake生成全攻略[zz]
  2. new new Foo().getName()面试题解析
  3. Linux网络知识--DHCP服务(理论部分)
  4. 02 视频或语音转文本
  5. 精读《图解密码技术》--第一章 环游密码世界
  6. readiness与liveness
  7. java身份证号/手机号隐藏中间几位
  8. R可视乎|创建乐高版马赛克图
  9. 5板斧---分析短信、彩信收发异常
  10. tyvj 1027 木瓜地 简单模拟