定义

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

说明

虚引用,正如其名,对一个对象而言,这个引用形同虚设,有和没有一样。

如果一个对象与GC Roots之间仅存在虚引用,则称这个对象为虚可达(phantom reachable)对象。

当试图通过虚引用的get()方法取得强引用时,总是会返回null,并且,虚引用必须和引用队列一起使用。既然这么虚,那么它出现的意义何在??

别慌别慌,自然有它的用处。它的作用在于跟踪垃圾回收过程,在对象被收集器回收时收到一个系统通知。 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,将这个虚引用加入引用队列,在其关联的虚引用出队前,不会彻底销毁该对象。 所以可以通过检查引用队列中是否有相应的虚引用来判断对象是否已经被回收了。

如果一个对象没有强引用和软引用,对于垃圾回收器而言便是可以被清除的,在清除之前,会调用其finalize方法,如果一个对象已经被调用过finalize方法但是还没有被释放,它就变成了一个虚可达对象。

与软引用和弱引用不同,显式使用虚引用可以阻止对象被清除,只有在程序中显式或者隐式移除这个虚引用时,这个已经执行过finalize方法的对象才会被清除。想要显式的移除虚引用的话,只需要将其从引用队列中取出然后扔掉(置为null)即可。

同样来看一个栗子:

public class PhantomReferenceTest {

private static final List TEST_DATA = new LinkedList<>();

private static final ReferenceQueue QUEUE = new ReferenceQueue<>();

public static void main(String[] args) {

TestClass obj = new TestClass("Test");

PhantomReference phantomReference = new PhantomReference<>(obj, QUEUE);

// 该线程不断读取这个虚引用,并不断往列表里插入数据,以促使系统早点进行GC

new Thread(() -> {

while (true) {

TEST_DATA.add(new byte[1024 * 100]);

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

Thread.currentThread().interrupt();

}

System.out.println(phantomReference.get());

}

}).start();

// 这个线程不断读取引用队列,当弱引用指向的对象呗回收时,该引用就会被加入到引用队列中

new Thread(() -> {

while (true) {

Reference extends TestClass> poll = QUEUE.poll();

if (poll != null) {

System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);

System.out.println("--- 回收对象 ---- " + poll.get());

}

}

}).start();

obj = null;

try {

Thread.currentThread().join();

} catch (InterruptedException e) {

e.printStackTrace();

System.exit(1);

}

}

static class TestClass {

private String name;

public TestClass(String name) {

this.name = name;

}

@Override

public String toString() {

return "TestClass - " + name;

}

}

}

使用的虚拟机设置如下:

-verbose:gc -Xms4m -Xmx4m -Xmn2m

运行结果如下:

[GC (Allocation Failure) 1024K->432K(3584K), 0.0113386 secs]

[GC (Allocation Failure) 1455K->520K(3584K), 0.0133610 secs]

[GC (Allocation Failure) 1544K->648K(3584K), 0.0008654 secs]

null

null

null

[GC (Allocation Failure) 1655K->973K(3584K), 0.0008111 secs]

null

...省略几个null的输出

[GC (Allocation Failure) 1980K->1997K(3584K), 0.0009289 secs]

[Full GC (Ergonomics) 1997K->1870K(3584K), 0.0048483 secs]

--- 弱引用对象被jvm回收了 ---- java.lang.ref.PhantomReference@74cbe23d

--- 回收对象 ---- null

null

...省略几个null和几次Full GC的输出

[Full GC (Ergonomics) 2971K->2971K(3584K), 0.0024850 secs]

[Full GC (Allocation Failure) 2971K->2971K(3584K), 0.0022460 secs]

Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space

at weakhashmap.PhantomReferenceTest.lambda$main$0(PhantomReferenceTest.java:20)

at weakhashmap.PhantomReferenceTest$$Lambda$1/2065951873.run(Unknown Source)

at java.lang.Thread.run(Thread.java:748)

因为设置的虚拟机堆大小比较小,所以创建一个100k的对象时直接进入了老年代,等到发生Full GC时才会被扫描然后回收。

适用场景

使用虚引用的目的就是为了得知对象被GC的时机,所以可以利用虚引用来进行销毁前的一些操作,比如说资源释放等。这个虚引用对于对象而言完全是无感知的,有没有完全一样,但是对于虚引用的使用者而言,就像是待观察的对象的把脉线,可以通过它来观察对象是否已经被回收,从而进行相应的处理。

事实上,虚引用有一个很重要的用途就是用来做堆外内存的释放,DirectByteBuffer就是通过虚引用来实现堆外内存的释放的。

小结

虚引用是最弱的引用

虚引用对对象而言是无感知的,对象有虚引用跟没有是完全一样的

虚引用不会影响对象的生命周期

虚引用可以用来做为对象是否存活的监控

java的虚引用_你不可不知的Java引用类型之——虚引用相关推荐

  1. java reference详解_你不可不知的Java引用类型之——Reference源码解析

    定义 Reference是所有引用类型的父类,定义了引用的公共行为和操作. reference指代引用对象本身,referent指代reference引用的对象,下文介绍会以reference,ref ...

  2. 的引用_懵!啥是Java软引用、弱引用、虚引用?

    小Hub领读: 深层次分析,有谁看懂了,点个赞看看?我一脸懵逼进来,一脸懵逼出去~ 作者:木枣粽子 https://juejin.im/post/6854573215767855117 在 Java ...

  3. java底层原理书籍_阿里面试题:Java中this和super关键字的底层实现原理

    知道的越多,不知道的就越多,业余的像一棵小草! 编辑:业余草 来源:https://www.xttblog.com/?p=5028 B 站:业余草 最近一个粉丝加我说,接到了阿里的面试,问问我阿里会面 ...

  4. java azure blob 查询_快速入门:适用于 Java 的 Azure Blob 存储客户端库 v8 | Microsoft Docs...

    您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn. 快速入门:使用 Jav ...

  5. java 优秀源码_想要快速进阶Java架构师?这份超强(长)学习计划单 请签收!...

    优秀工程师的成长之路就是一条不断打怪升级之路的"修仙之路"! 而Java程序员一向比别人更难,如果说大家都在修仙的话,java程序员简直神似"剑修",入行枯燥精 ...

  6. java编译器jdk版本_以编程方式确定Java类的JDK编译版本

    java编译器jdk版本 当需要确定使用哪个JDK版本来编译特定的Java .class文件时, 通常使用的方法是使用javap并在javap输出中查找列出的"主要版本". 我在我 ...

  7. java护照号码校验_学无止境之小白学java……第001天

    学习主题:预科阶段 对应视频: http://www.itbaizhan.cn/course/id/18.html 对应作业: 1. 为什么需要学编程,什么样的人可以做程序员? 编程是现实逻辑的表达, ...

  8. java的字符串复制_我应该如何复制Java中的字符串?

    String s = "hello"; String backup_of_s = s; s = "bye"; 在这一点上,备份变量仍然包含原始值"he ...

  9. java青蛙过河打字_趣味算法——青蛙过河(JAVA)

    青蛙过河是一个非常有趣的智力游戏,其大意如下: 一条河之间有若干个石块间隔,有两队青蛙在过河,每队有3只青蛙,这些青蛙只能向前移动,不能向后移动,且一次只能有一只青蛙向前移动.在移动过程中,青蛙可以向 ...

最新文章

  1. linux时间和时区修改(附suse)
  2. 汇编语言--CMOS RAM芯片
  3. Oracle 跨resetlogs的恢复
  4. Linux文件目录及其作用
  5. GCC 中文手册 - 摘自纯C论坛
  6. 漫步数学分析一——实数轴
  7. [原创]按键小精灵通用去广告破解补丁
  8. linux io测试陈旭,130242014076+陈旭+第2次实验(示例代码)
  9. Runner站立会议06
  10. 如何在Angular 2项目中使用Bootstrap css库
  11. 复函数图像怎么画_matlab复变函数画图形
  12. 苹果Mac环境如何配置定时任务?
  13. 技术要求→物理安全→防雷击
  14. JS定义const常量对象
  15. php框架thinkphp教程,thinkPHP5.0框架安装教程详解
  16. oracle px execute reply,(转)PX Deq: Execute Reply 案例说明
  17. 鹅厂同学:7 月开始不再进行薪酬调整?
  18. 【听书笔记-0515】-《清单革命》
  19. bat 打开常用软件
  20. lbs多城市切换php源码,多省份多城市多区县切换 专业版(dicky_multicityswitch) dz插件分享,可以随意切换到其它地区分站功能...

热门文章

  1. Nature子刊:华中农大Kenichi Tsuda组利用植物体内原位细菌转录及蛋白组学鉴定寄主免疫攻击的病原菌蛋白...
  2. 支付宝蚂蚁森林合种树,2-4天领证,1/2号车满员,3号车成立
  3. 鱼和熊掌可以兼得! 天昊生物微生物16S扩增子绝对定量测序检测新模式创双赢!...
  4. R语言使用ggplot2包使用geom_boxplot函数绘制基础分组箱图(配置数据点显示)实战
  5. R语言使用ggplot2包使用geom_violin函数绘制小提琴图(水平小提琴图、垂直小提琴图、边缘不截断小提琴图)实战
  6. python使用fpdf生成pdf章节(chapter)文件包含:页眉、页脚、章节主体、章节内容等;
  7. R安装包源设置的常见方式及国内常用源
  8. 自然语言处理NLP之文本蕴涵、智能问答、语音识别、对话系统、文本分类、情感计算
  9. 无人驾驶之车道线检测简易版
  10. KNN 最近邻算法(K近邻)