深入了解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 虚引用的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java中弱引用和软引用的区别以及虚引用和强引用介绍

    知道弱引用和软引用的概念与如何使用它们是两码事,引用类在垃圾回收工作的过程中有重要作用.我们都知道垃圾回收器会回收符合回收条件的对象的内存,但并不是所有的程序员都知道回收条件取决于指向该对象的引用类型.这正是Java中弱引用和软引用的主要区别.如果一个对象只有弱引用指向它,垃圾回收器会立即回收该对象,这是一种急切回收方式.相对的,如果有软引用指向这些对象,则只有在JVM需要内存时才回收这些对象.弱引用和软引用的特殊行为使得它们在某些情况下非常有用.例如:软引用可以很好的用来实现缓存,当JVM需要

  • 深入了解JAVA 软引用

    定义 软引用是使用SoftReference创建的引用,强度弱于强引用,被其引用的对象在内存不足的时候会被回收,不会产生内存溢出. 说明 软引用,顾名思义就是比较"软"一点的引用. 当一个对象与GC Roots之间存在强引用时,无论何时都不会被GC回收掉.如果一个对象与GC Roots之间没有强引用与其关联而存在软引用关联时,那么垃圾回收器对它的态度就取决于内存的紧张程度了.如果内存空间足够,垃圾回收器就不会回收这个对象,但如果内存空间不足了,它就难逃被回收的厄运. 如果一个对象与GC

  • java通过实例了解值传递和引用传递

    这篇文章主要介绍了java通过实例了解值传递和引用传递,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.java中的值传递的问题 指的是在方法调用时,传递的参数是按值的拷贝传递.示例如下: public static void main(String[] args) { int a=1; change(a); System.out.println("交换a后的值:"+a); } private static void change(

  • 基于java读取并引用自定义配置文件

    首先在resources目录创建自定义的配置文件 配置文件的格式: 写工具类,得到配置参数 import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class MyConfig { public static Properties myProp = new Properties(); public static InputStream myResource = MyCo

  • 详解JAVA 弱引用

    定义 弱引用是使用WeakReference创建的引用,弱引用也是用来描述非必需对象的,它是比软引用更弱的引用类型.在发生GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收. 说明 弱引用,从名字来看就很弱嘛,这种引用指向的对象,一旦在GC时被扫描到,就逃脱不了被回收的命运. 但是,弱引用指向的对象也并不一定就马上会被回收,如果弱引用对象较大,直接进到了老年代,那么就可以苟且偷生到Full GC触发前,所以弱引用对象也可能存在较长的一段时间.一旦一个弱引用对象被垃圾回收器回收,便

  • Java中强引用,软引用,弱引用概念解析

    1.概念解释强引用是使用最普遍的引用:Object o=new Object(); 特点:不会被GC 将对象的引用显示地置为null:o=null; // 帮助垃圾收集器回收此对象 举例ArrayList的实现源代码: &amp;lt;img src="https://pic2.zhimg.com/50/dd6f826c4e0c045f3701978f311636e1_hd.png" data-rawwidth="361" data-rawheight=&q

  • 详解JAVA 强引用

    定义 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器宁愿抛出OOM(OutOfMemoryError)也不会回收它. 说明 不要被这个强字吓到,以为这个引用就很厉害,其实强引用就是程序中使用的一般引用类型.举个简单的栗子: String s = new String("Hello Frank!"); 强可达 如果一个对象与GC Roots之间存在强引用,则称这个对象为强可达(strong reachable)对象. 当你声明一个变量并指向一个实例的时候,其实就是在创造一

  • Java中值类型和引用类型的比较与问题解决

    一.问题描述 前几天因为一个需求出现了Bug.说高级点也挺高级,说白点也很简单.其实也就是一个很简单的Java基础入门时候的值类型和引用类型的区别.只是开发的时候由于自己的问题,导致小问题的出现.还好突然想起来以前看过一篇对于该问题讲解的博客,才能快速定位问题的位置.防止下次再犯,顺便也就把这个当做笔记记录下来,放入自己的Bug集中. 二.值类型和引用类型的比较 这个大家应该都是没问题的,很简单.值类型比较是比较值,引用类型是比较地址.对于正常的操作来说,比较值类型我们可以直接使用 == ,引用

  • 详解JAVA 虚引用

    定义 虚引用是使用PhantomReference创建的引用,虚引用也称为幽灵引用或者幻影引用,是所有引用类型中最弱的一个.一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用获得一个对象实例. 说明 虚引用,正如其名,对一个对象而言,这个引用形同虚设,有和没有一样. 如果一个对象与GC Roots之间仅存在虚引用,则称这个对象为虚可达(phantom reachable)对象. 当试图通过虚引用的get()方法取得强引用时,总是会返回null,并且,虚引用必须和引用队列一

  • 深入了解JAVA 虚引用

    定义 虚引用是使用PhantomReference创建的引用,虚引用也称为幽灵引用或者幻影引用,是所有引用类型中最弱的一个.一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用获得一个对象实例. 说明 虚引用,正如其名,对一个对象而言,这个引用形同虚设,有和没有一样. 如果一个对象与GC Roots之间仅存在虚引用,则称这个对象为虚可达(phantom reachable)对象. 当试图通过虚引用的get()方法取得强引用时,总是会返回null,并且,虚引用必须和引用队列一

  • 详解Java对象的强、软、弱和虚引用+ReferenceQueue

    详解Java对象的强.软.弱和虚引用+ReferenceQueue 一.强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回收它.当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题. 二.软引用(SoftReference) 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它:如果内存空间不足了,就会回收这些对象的内存.只要垃圾回

  • Java引用队列和虚引用实例分析

    本文实例讲述了Java引用队列和虚引用.分享给大家供大家参考,具体如下: 一 点睛 引用队列由ReferenceQueue类表示,它用于保存被回收后对象的引用.当联合使用软引用.弱引用和引用队列时,系统在回收被引用的对象之后,将把它所回收对象对应的引用添加到关联的引用队列中.而虚引用在对象被释放之前,将把它对应的虚引用添加到它关联的引用队列中,这使得可以在对象被回收之前采取行动. 虚引用无法获取它所对应的对象. 二 实战 1 代码 import java.lang.ref.*; public c

  • Java中的强引用,软引用,弱引用,虚引用的作用介绍

    目录 1.强引用(StrongReference) 2.软引用(SoftReference) 3.弱引用(WeakReference) 4.虚引用(PhantomReference) 5.强引用>软引用>弱引用>虚引用 1.强引用( Strong Reference ) 最普遍的引用:Object obj=new Object()抛出OutOfMemoryError终止程序也不会回收具有强引用的对象通过将对象设置为null来弱化引用,使其被回收 2.软引用( Soft Reference

  • 详解Java弱引用(WeakReference)的理解与使用

    看到篇帖子, 国外一个技术面试官在面试senior java developer的时候, 问到一个weak reference相关的问题. 他没有期望有人能够完整解释清楚weak reference是什么, 怎么用, 只是期望有人能够提到这个concept和java的GC相关. 很可惜的是, 20多个拥有5年以上java开发经验的面试者中, 只有两人知道weak reference的存在, 而其中只有一人实际用到过他. 无疑, 在interviewer眼中, 对于weak reference的理

随机推荐