你不可不知的Java引用类型之——虚引用
定义
虚引用是使用PhantomReference创建的引用,虚引用也称为幽灵引用或者幻影引用,是所有引用类型中最弱的一个。一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用获得一个对象实例。
说明
虚引用,正如其名,对一个对象而言,这个引用形同虚设,有和没有一样。
如果一个对象与GC Roots之间仅存在虚引用,则称这个对象为
虚可达(phantom reachable)对象。
当试图通过虚引用的get()方法取得强引用时,总是会返回null,并且,虚引用必须和引用队列一起使用。既然这么虚,那么它出现的意义何在??
别慌别慌,自然有它的用处。它的作用在于跟踪垃圾回收过程,在对象被收集器回收时收到一个系统通知。 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,将这个虚引用加入引用队列,在其关联的虚引用出队前,不会彻底销毁该对象。 所以可以通过检查引用队列中是否有相应的虚引用来判断对象是否已经被回收了。
如果一个对象没有强引用和软引用,对于垃圾回收器而言便是可以被清除的,在清除之前,会调用其finalize方法,如果一个对象已经被调用过finalize方法但是还没有被释放,它就变成了一个虚可达对象。
与软引用和弱引用不同,显式使用虚引用可以阻止对象被清除,只有在程序中显式或者隐式移除这个虚引用时,这个已经执行过finalize方法的对象才会被清除。想要显式的移除虚引用的话,只需要将其从引用队列中取出然后扔掉(置为null)即可。
同样来看一个栗子:
public class PhantomReferenceTest {
private static final List<Object> TEST_DATA = new LinkedList<>();
private static final ReferenceQueue<TestClass> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
TestClass obj = new TestClass("Test");
PhantomReference<TestClass> 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引用类型之——软引用
定义 软引用是使用SoftReference创建的引用,强度弱于强引用,被其引用的对象在内存不足的时候会被回收,不会产生内存溢出. 说明 软引用,顾名思义就是比较"软"一点的引用. ...
- 你不可不知的Java引用类型之——弱引用
定义 弱引用是使用WeakReference创建的引用,弱引用也是用来描述非必需对象的,它是比软引用更弱的引用类型.在发生GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收. 说明 弱 ...
- 你不可不知的Java引用类型之——强引用
定义 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器宁愿抛出OOM(OutOfMemoryError)也不会回收它. 说明 不要被这个强字吓到,以为这个引用就很厉害,其实强引用就是程序 ...
- Java引用类型之软引用(1)
Java使用SoftReference来表示软引用,软引用是用来描述一些“还有用但是非必须”的对象.对于软引用关联着的对象,在JVM应用即将发生内存溢出异常之前,将会把这些软引用关联的对象列进去回收对 ...
- Java引用类型之软引用(2)
下面接着上一篇介绍第2阶段和第3阶段的处理逻辑. 2.process_phase2() 第2个阶段移除所有的referent还存活的Reference,也就是从refs_list中移除Referenc ...
- Java引用类型之弱引用与幻像引用
这一篇将介绍弱引用和幻像引用. 1.WeakReference WeakReference也就是弱引用,弱引用和软引用类似,它是用来描述"非必须"的对象的,它的强度比软引用要更弱一 ...
- Java引用类型之最终引用
FinalReference类只有一个子类Finalizer,并且Finalizer由关键字final修饰,所以无法继承扩展.类的定义如下: class FinalReference<T> ...
- 你不可不知的Java引用类型【总结篇】
四种引用类型总结 引用级别:强引用 > 软引用 > 弱引用 > 虚引用 理解 就如最开始说的,设置四种引用类型,是为了更好的控制对象的生命周期,让代码能够一定程度上干涉GC过程,所以 ...
- 你不可不知的Java引用类型之——ReferenceQueue源码详解
定义 ReferenceQueue是引用队列,用于存放待回收的引用对象. 说明 对于软引用.弱引用和虚引用,如果我们希望当一个对象被垃圾回收器回收时能得到通知,进行额外的处理,这时候就需要使用到引用队 ...
随机推荐
- .Net RabbitMQ之消息通信 构建RPC服务器
1.消息投递服务 RabbitMQ是一种消息投递服务,怎么理解这句话呢?即RabbitMQ即不是消息的生产者,也是消息的消费者.他就像现实生活中快递模式,消费者在电商网站上下单买了一件商品,此时对应的 ...
- Linux编程 14 文件权限(用户列表passwd,用户控制shadow,useradd模板与useradd命令参数介绍)
一. 概述 linux安全系统的核心是用户账户. 创建用户时会分配用户ID(UID). UID是唯一的,但在登录系统时不是用UID,而是用登录名.在讲文件权限之之前,先了解下linux是怎样处理用户账 ...
- Google的java工具类Guava
前言 google开发java项目肯定也不想重复造轮子,所以肯定也有工具类,就是它了:Guava 我将举例几个实际的例子,发挥这个工具类好用的功能.更多的方法和功能,还有内部的实现可以直接参考http ...
- 网络编程第三讲UDP编写
网络编程第三讲UDP编写 一丶UDP简介 UDP是面向无连接的.就是说数据传输会丢掉.网络延时比较大的情况下.会早上丢包.例如视频通话.就是UDP UDP不需要建立建立. 下面有UDP编写流程图 下图 ...
- Map<String, Object>转Object,Object转 Map<String, Object>
Map转Object import com.alibaba.fastjson.JSON; Map<String, Object> boneAgeOrderMap=boneAgeOrderS ...
- PHP中的__set和__get方法
当调用或者设置类不存在的方法时,_会调用_set和__get方法 以下是示例 <?php class HandsonBoy { private $name = 'chenqionghe'; pr ...
- Python机器学习笔记:XgBoost算法
前言 1,Xgboost简介 Xgboost是Boosting算法的其中一种,Boosting算法的思想是将许多弱分类器集成在一起,形成一个强分类器.因为Xgboost是一种提升树模型,所以它是将许多 ...
- 深入MySQL复制(三):半同步复制
1.半同步复制 半同步复制官方手册:https://dev.mysql.com/doc/refman/5.7/en/replication-semisync.html 默认情况下,MySQL的复制是异 ...
- CSRF跨站伪造请求
一.什么是CSRF CSRF(Cross Site Request Forgery) 跨站请求伪造.也被称为One Click Attack和Session Riding,通常缩写为CSRF或XSRF ...
- 分享一个爬取HUST(哈理工)学生成绩的Python程序(OCR自动识别验证码)
Python版本:3.5.2 日期:2018/1/21 __Author__ = "Lance#" # -*- coding = utf-8 -*- from urllib imp ...