2020-01-09 16:47·澳门威尼斯巴黎人

一. 简介

在看ThreadLocal源码的时候,此中嵌套类ThreadLocalMap中的Entry世袭了WeakReferenc,为了能搞清楚ThreadLocal,只可以先明白下了WeakReferenc(是的,非常多时候为了搞明白叁个事物,必须要往上追好几层,先搞清楚其所信赖的东西。卡塔尔国上面步入正题,WeakReference如字面意思,弱引用, 当一个对象只是被weak reference指向, 而未有任何其它strong reference指向的时候, 若是那时GC运维, 那么这一个目的就能够被回笼,无论当前的内部存储器空间是不是丰裕,这么些目的都会被回笼。

  1 背景
  
  某一天在某贰个群里面包车型客车某部群友忽地提议了叁个标题:"threadlocal的key是虚引用,那么在threadlocal.get(卡塔尔的时候,产生GC之后,key是不是是null?"显示器前的您能够能够的构思那一个标题,在那处作者先卖个枢纽,先讲讲Java中援用和ThreadLocal的那么些事。
  
  2 Java中的援用
  
  对于大多Java初读书人的话,会把援用和目的给搞混淆。上面有大器晚成段代码,
  
  User zhangsan = new User("zhangsan", 24);
  
  这里先提个难题zhangsan到底是援用依旧对象啊?超多个人会感到zhangsan是个指标,假若你也是这样感到的话那么再看一下底下后生可畏段代码
  
  User zhangsan;
  
  zhangsan = new User("zhangsan", 24);
  
  这段代码和始发的代码其实施行职能是风度翩翩律的,这段代码的第生机勃勃行User zhangsan,定义了zhangsan,那您觉得zhangsan还是对象呢?倘使你还以为的话,那么这一个目的应当是何许吗?的确,zhangsan其实只是二个引用,对JVM内部存款和储蓄器划分驾驭的同学应该精通上边包车型地铁图片:
  
  其实zhangsan是栈中分配的三个援用,而new User("zhangsan", 24卡塔尔国是在堆中分配的多少个对象。而'='的效能是用来将援引指向堆中的对象的。就如您叫张三但张三是个名字而已并非多少个事实上的人,他只是指向的您。
  
  大家日常所说的引用其实都以代指的强引用,在JDK1.2后头援引不仅仅那黄金年代种,平日的话分为多样:强引用,软援用,弱援用,虚援用。而接下去笔者会风华正茂一介绍那各样援引。
  
  2.1 强引用
  
  上面大家说过了 User zhangsan = new User("zhangsan", 24State of Qatar;这种正是强援引,有一点点相符C的指针。对强援用他的特点有下边多少个:
  
  强引用能够一向访谈目的对象。
  
  只要那几个指标被强引用所提到,那么垃圾回笼器都不会回笼,那怕是抛出OOM分外。
  
  轻巧形成内部存款和储蓄器泄漏。
  
  2.2 软引用
  
  在Java中运用SoftReference协助大家定义软引用。其布局方法有三个:
  
  public SoftReference(T referent);
  
  public SoftReference(T referent, ReferenceQueue<? super T> q);
  
  七个构造方法相近,第一个比第一个多了一个援用队列,在布局方法中的第二个参数便是大家的其实被针没有错对象,这里用新建多个SoftReference来代替大家地方强援引的等号。 下边是组织软引用的例证:
  
  softZhangsan = new SoftReference(new User("zhangsan", 24));
  
  2.2.1软援用有如何用?
  
  假使有个别对象他只被软援引所针对,那么她将会在内部存款和储蓄器要溢出的时候被回笼,也正是当大家要出现OOM的时候,借使回笼了一波内部存款和储蓄器还远远不够,那才抛出OOM,弱援用回笼的时候要是设置了引用队列,那么这么些软援用还有大概会进三回援用队列,不过援引所针对的靶子已经被回笼。这里要和上面包车型客车弱援引区分开来,弱援引是假若有垃圾回笼,那么她所针没错靶子就能够被回笼。上面是叁个代码例子:
  
  public static void main(String[] args) {
  
  ReferenceQueue<User> referenceQueue = new ReferenceQueue();
  
  SoftReference softReference = new SoftReference(new User("zhangsan",24), referenceQueue);
  
  //手动触发GC
  
  System.gc();
  
  Thread.sleep;
  
  System.out.println("手动触发GC:" + softReference.get;
  
  System.out.println("手动触发的种类:" + referenceQueue.poll(www.yongshi123.cn卡塔尔(قطر‎卡塔尔;
  
  //通过堆内部存款和储蓄器不足触发GC
  
  makeHeapNotEnough();
  
  System.out.println("通过堆内部存款和储蓄器不足触发GC:" + softReference.get;
  
  System.out.println("通过堆内部存款和储蓄器不足触发GC:" + referenceQueue.poll;
  
  }
  
  private static void makeHeapNotEnough() {
  
  SoftReference softReference = new www.dfgjpt.com SoftReference(new byte[1024*1024*5]);
  
  byte[] bytes =www.tiaotiaoylzc.com new byte[1024*1024*5];
  
  }
  
  输出:
  
  手动触发GC:User{name='zhangsan', age=24}
  
  手动触发的行列:null
  
  通过堆内存不足触发GC:null
  
  通过堆内部存款和储蓄器不足触发GC:java.lang.ref.SoftReference@4b85612c
  
  通过-Xmx10m安装我们堆内部存款和储蓄器大小为10,方便布局堆内部存款和储蓄器不足的情况。可以瞥见大家输出的情况大家手动调用System.gc并未回笼我们的软引用所针对的指标,只有在内部存款和储蓄器不足的事态下技艺接触。
  
  2.2.2软应用的利用
  
  在SoftReference的doc中有与此相类似一句话:
  
  Soft references are most often used to implement memory-sensitive caches
  
  也正是说软援引平常用来兑现内部存款和储蓄器敏感的高速缓存。怎么明白那句话呢?我们了解软援用他只会在内部存款和储蓄器不足的时候才触发,不会像强引用那用轻易内部存款和储蓄器溢出,大家得以用其完成高速缓存,一方面内部存款和储蓄器不足的时候能够回笼,一方面也不会频仍回笼。在高速本地缓存Caffeine中落实了软引用的缓存,当需求缓存淘汰的时候,借使是只有软援用指向那么久会被回笼。不熟稔Caffeine的同校可以阅读深远理解Caffeine
  
  2.3 弱引用
  
  弱援引在Java中选用WeakReference来定义多少个弱援用,上面大家说过她比软援引特别弱,只要产生垃圾回笼,若那一个目的只被弱引用指向,那么就能够被回笼。这里大家就没有多少废话了,直接上例子:
  
  public static void main(String[www.yongshiyule178.com] args) {
  
  WeakReference weakReference = new WeakReference(new User("zhangsan",24));
  
  System.gc();
  
  System.out.println("手动触发GC:" + weakReference.get;
  
  }
  
  输出结果:
  
  手动触发GC:null
  
  可以预知上边的事例只要垃圾回笼一触发,该指标就被回笼了。
  
  2.3.1 弱援用的成效
  
  在WeakReference的注释中写到:
  
  Weak references are most often used to implement canonicalizing mappings.
  
  从当中能够明白虚援用越来越多的是用来兑现佳能icalizing mappings。在JDK中WeakHashMap很好的反映了这么些例子:
  
  public static void main(String[www.jiahuayulpt.com] args) throws Exception {
  
  WeakHashMap<User, String> weakHashMap = new WeakHashMap();
  
  //强引用
  
  User zhangsan = new User("zhangsan", 24);
  
  weakHashMap.put(zhangsan, "zhangsan");
  
  System.out.println("有强引用的时候:map大小" + weakHashMap.size;
  
科技世界,  //去掉强引用
  
  zhangsan = null;
  
  System.gc();
  
  Thread.sleep;
  
  System.out.println("无强援引的时候:map大小"+weakHashMap.size;
  
  }
  
  输出结果为:
  
  有强援用的时候:map大小1
  
  无强援引的时候:map大小0
  
  能够见到在GC之后大家在map中的键值对就被回笼了,在weakHashMap中其实唯有Key是虚援引做关联的,然后通过援引队列再去对大家的map进行回笼管理。
  
  2.4 虚引用
  
  虚援用是最弱的援用,在Java中选用PhantomReference进行定义。弱到什么程度吗?也正是您定义了虚引用根本比较小概通过虚引用赢获得那几个指标,更别谈影响这一个指标的生命周期了。在虚援用中举世无双的机能正是用队列接受指标将要葬身鱼腹的通知。
  
  public static void main(String[www.michenggw.com] args) throws Exception {
  
  ReferenceQueue referenceQueue = new ReferenceQueue(www.fengshen157.com );
  
  PhantomReference phantomReference www.huarenyl.cn= new PhantomReference(new User("zhangsan", 24), referenceQueue);
  
  System.out.println("什么也不做,获取:" + phantomReference.get;
  
  }
  
  输出结果:
  
  什么也不做,获取:null
  
  在PhantomReference的笺注中写到:
  
  Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.
  
  虚引用得最多的就是在对象死前所做的清理操作,那是一个比Java的finalization梗灵活的建制。 在DirectByteBuffer中利用Cleaner用来回笼对外内部存款和储蓄器,Cleaner是PhantomReference的子类,当DirectByteBuffer被回收的时候未幸免内部存款和储蓄器泄漏所以通过这种措施举办回笼,有一些雷同于上面包车型地铁代码:
  
  public static void main(String[www.jiuzhoyulpt.cn] args) throws Exception {
  
  Cleaner.create(new User("zhangsan", 24卡塔尔(قطر‎, (State of Qatar -> {System.out.println("我被回笼了,当前线程:{}"+ Thread.currentThread(www.yihuanyule.cn卡塔尔.getName;
  
  System.gc();
  
  Thread.sleep;
  
  }
  
  输出:
  
  我被回收了,当前线程:Reference Handler
  
  3 ThreadLocal
  
  ThreadLocal是叁个本土线程别本变量工具类,基本在大家的代码中随处可遇。这里就可是多的牵线她了。
  
  3.1 ThreadLocal和弱援引的那么些事
  
  上边说了如此多关于引用的事,这里总算回到了核心了小编们的ThreadLocal和弱援引有如何关联吗?
  
  在大家的Thread类中有下边那么些变量:
  
  ThreadLocal.ThreadLocalMap threadLocals
  
  ThreadLocalMap本质上也是个Map,当中Key是大家的ThreadLocal这些目的,Value便是大家在ThreadLocal中保留的值。也正是说大家的ThreadLocal保存和取对象都以由此Thread中的ThreadLocalMap来操作的,而key正是小编。在ThreadLocalMap中Entry犹如下概念:
  
  static class Entry extends WeakReference<ThreadLocal<?>> {
  
  /** The value associated with this ThreadLocal. */
  
  Object value;
  
  Entry(ThreadLocal<?> k, Object v) {
  
  super;
  
  value = v;
  
  }
  
  }
  
  可见Entry是WeakReference的子类,而以此虚引用所涉嫌的对象就是大家的ThreadLocal这几个目的。我们又再次回到地点的标题:
  
  "threadlocal的key是虚援用,那么在threadlocal.get(卡塔尔的时候,产生GC之后,key是还是不是是null?"
  
  那一个标题晃眼黄金时代看,虚引用嘛,还也许有垃圾回笼那断定是为null,那实乃不没错,因为难点说的是在做threadlocal.get(卡塔尔操作,阐明实际仍然有强引用存在的。所以key并不为null。若是我们的强援引子虚乌有的话,那么Key就能够被回笼,也便是会现身大家value没被回笼,key被回笼,导致value恒久存在,出现内部存款和储蓄器泄漏。那也是ThreadLocal日常会被比相当多书籍提示到需求remove(卡塔尔的来由。
  
  你或者会问见到许多源码的ThreadLocal并不曾写remove照旧再用得很好呢?那实乃因为不菲源码平日是用作静态变量存在的生命周期和Class是相通的,而remove必要再那么些方法或然目的里面使用ThreadLocal,因为方法栈恐怕指标的销毁进而强援引错过,导致内存泄漏。
  
  3.2 FastThreadLocal
  
  法斯特ThreadLocal是Netty中提供的高质量本地线程别本变量工具。在Netty的io.netty.util中提供了成都百货上千屌爆了的工具,后续会挨个给我们介绍,这里就先说下法斯特ThreadLocal。
  
  法斯特ThreadLocal有下边多少个特点:
  
  使用数组代替ThreadLocalMap存款和储蓄数据,从而得到更加快的性质。(缓存行和三次定位,不会有hash冲突卡塔尔
  
  由于应用数组,不会冒出Key回笼,value没被回笼的难堪局面,所防止止了内部存款和储蓄器泄漏。
  
  总结
  
  小说开头的主题材料,为何会被问出来,其实是对虚援用和ThreadLocal驾驭不深以致,非常多时候只记着一个只假使虚引用,在废品回笼时就能够被回笼,就可诱致使把这一个古板先入之见,未有做越多的剖判考虑。所以我们再解析叁个主题材料的时候还是须要更加多的站在分裂的情景上做越多的考虑。

对象意况

科技世界 1

  • 可达状态:
    有叁个以上的援引变量引用此指标

  • 可过来状态:
    大器晚成经程序中有个别对象不再有别的的引用变量引用它,它将先进入可还原情形,系统的垃圾回笼机制准备回笼该对象的所占用的内部存款和储蓄器,在回笼以前,系统会调用finalize(卡塔尔方法举行财富清理,假使能源收拾后再度让一个之上援用变量引用该对象,则那几个目的会重新成为可达状态,不然就能够跻身不可达状态。

  • 不可达状态:
    当目的的兼具涉嫌都被割裂,且系统调用finalize(卡塔尔方法实行财富清理后仍然未有使该指标形成可达状态,则那几个指标将永远性失去援用并且产生不可达状态,系统才会真的的去回笼该对象所占有的财富。

System.out.println(sf);

三. 使用WeakReference

上面是采用持续WeakReference的措施来使用软援引,而且不采取ReferenceQueue。

package io.github.brightloong.lab.reference;/** * Apple class * * @author BrightLoong * @date 2018/5/25 */public class Apple { private String name; public Apple(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } /** * 覆盖finalize,在回收的时候会执行。 * @throws Throwable */ @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("Apple: " + name + " finalize。"); } @Override public String toString() { return "Apple{" + "name='" + name + '\'' + '}' + ", hashCode:" + this.hashCode(); }}

package io.github.brightloong.lab.reference;import java.lang.ref.WeakReference;/** * Salad class * 继承WeakReference,将Apple作为弱引用。 * 注意到时候回收的是Apple,而不是Salad * * @author BrightLoong * @date 2018/5/25 */public class Salad extends WeakReference<Apple> { public Salad(Apple apple) { super; }}

package io.github.brightloong.lab.reference;import java.lang.ref.WeakReference;/** * Main class * * @author BrightLoong * @date 2018/5/24 */public class Client { public static void main(String[] args) { Salad salad = new Salad(new Apple; //通过WeakReference的get()方法获取Apple System.out.println("Apple:" + salad.get; System.gc(); try { //休眠一下,在运行的时候加上虚拟机参数-XX:+PrintGCDetails,输出gc信息,确定gc发生了。 Thread.sleep; } catch (InterruptedException e) { e.printStackTrace(); } //如果为空,代表被回收了 if (salad.get() == null) { System.out.println("clear Apple。"); } }}

出口如下:

Apple:Apple{name='红富士'}, hashCode:1846274136[GC (System.gc [PSYoungGen: 3328K->496K] 3328K->504K, 0.0035102 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] [Full GC (System.gc [PSYoungGen: 496K->0K] [ParOldGen: 8K->359K] 504K->359K, [Metaspace: 2877K->2877K], 0.0067965 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Apple: 红富士 finalize。clear Apple。

package io.github.brightloong.lab.reference;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.ref.WeakReference;/** * Client2 class * * @author BrightLoong * @date 2018/5/27 */public class Client2 { public static void main(String[] args) { ReferenceQueue<Apple> appleReferenceQueue = new ReferenceQueue<>(); WeakReference<Apple> appleWeakReference = new WeakReference<Apple>(new Apple, appleReferenceQueue); WeakReference<Apple> appleWeakReference2 = new WeakReference<Apple>(new Apple, appleReferenceQueue); System.out.println("=====gc调用前====="); Reference<? extends Apple> reference = null; while ((reference = appleReferenceQueue.poll != null ) { //不会输出,因为没有回收被弱引用的对象,并不会加入队列中 System.out.println(reference); } System.out.println(appleWeakReference); System.out.println(appleWeakReference2); System.out.println(appleWeakReference.get; System.out.println(appleWeakReference2.get; System.out.println("=====调用gc====="); System.gc(); try { Thread.sleep; } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("=====gc调用后====="); //下面两个输出为null,表示对象被回收了 System.out.println(appleWeakReference.get; System.out.println(appleWeakReference2.get; //输出结果,并且就是上面的appleWeakReference、appleWeakReference2,再次证明对象被回收了 Reference<? extends Apple> reference2 = null; while ((reference2 = appleReferenceQueue.poll != null ) { //如果使用继承的方式就可以包含其他信息了 System.out.println("appleReferenceQueue中:" + reference2); } }}

结果输出如下:

=====gc调用前=====java.lang.ref.WeakReference@6e0be858java.lang.ref.WeakReference@61bbe9baApple{name='青苹果'}, hashCode:1627674070Apple{name='毒苹果'}, hashCode:1360875712=====调用gc=====Apple: 毒苹果 finalize。Apple: 青苹果 finalize。=====gc调用后=====nullnullappleReferenceQueue中:java.lang.ref.WeakReference@6e0be858appleReferenceQueue中:java.lang.ref.WeakReference@61bbe9baProcess finished with exit code 0

能够看到在队列中(ReferenceQueue),调用gc早前是还未内容的,调用gc之后,对象被回笼了,并且弱援引对象appleWeakReference和appleWeakReference2被放入了队列中。

有关其余三种援用,强援引、软援引、虚援用,可以参考

StrongReference

默许引用完成,当未有别的对象指向它时,GC推行后将会被回笼

Food food = new Food();
food = null;

}

二. 认识WeakReference类

WeakReference世袭Reference,在那之中独有七个布局函数:

public class WeakReference<T> extends Reference<T> { public WeakReference(T referent) { super; } public WeakReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); }}
  • WeakReference(T referent卡塔尔国:referent正是被弱引用的目的(注意区分弱援引对象和被弱引用的照顾,弱援引对象是指WeakReference的实例或然其子类的实例),例如有贰个Apple实例apple,能够如下使用,並且经过get(卡塔尔(قطر‎方法来博取apple引用。也足以再成立贰个持续WeakReference的类来对Apple举办弱援引,上面就能够选取这种格局。
WeakReference<Apple> appleWeakReference = new WeakReference<>;Apple apple2 = appleWeakReference.get();
  • WeakReference(T referent, ReferenceQueue<? super T> qState of Qatar:与地点的布局方法相比较,多了个ReferenceQueue,在目的被回笼后,会把弱援引对象,也正是WeakReference对象或然其子类的靶子,放入队列ReferenceQueue中,注意不是被弱援引的对象,被弱援引的对象已经被回笼了。

引用

级别: 强引用 > 软引用 > 弱引用 > 虚引用

Object ref =newObject(State of Qatar;//ref是Object对象的强援引

科技世界 2WeakReference阅读原著请访谈小编的博客布WrightLoong's Blog

垃圾堆回笼

垃圾回笼回调方法:

  • finalize(卡塔尔(قطر‎函数是在JVM回笼内部存款和储蓄器时实施的,但JVM并不保障在回笼内部存款和储蓄器时一定会调用finalize(卡塔尔。

JVM的废料回笼机制:

  • 在内部存款和储蓄器丰盛的景观下,显式调用System.gc(卡塔尔(system.gc调用仅仅是建议虚构机进行回笼,并不一定立即会开展gc卡塔尔
  • 在内部存款和储蓄器不足的情事下,垃圾回笼将机关运行

publicstaticvoidmain(String[] args) {

SoftReference

临近WeakReference,但SoftReference会尽恐怕长的保留援引直到JVM内存不足时才会被回笼, 切合缓存应用

管理进度同WeakReference

Food food = new Food();
SoftReference<Food> softFood = new  SoftReference<Food>(food);
food = null;
// JVM OutOfMemory

动用:轻便对象cache

A obj = new A();
SoftRefenrence sr = new SoftReference(obj);
//引用时
if(sr!=null){
   obj = sr.get();
}else{
  obj = new A();
  sr = new SoftReference(obj);
}

ReferenceQueue

WeakReference

所引述的对象在JVM内不再有强援引时,GC实行后将会被回笼

管理进度:

  • WeakReference对象的referent域被安装为null,进而使该对象不再援用heap对象。
  • WeakReference引用过的heap对象被声称为finalizable。
  • 再者依旧风姿洒脱段时间后WeakReference对象被加多到它的ReferenceQueue(倘若ReferenceQueue存在的话卡塔尔国。

对于软引用和弱援引,入队和finalize方法的奉行是从未稳固顺序的

 Food food = new Food();
 WeakReference<Food> weakFood = new      WeakReference<Food>(food);
 food = null;

动用:任何时候获得某指标的新闻(不影响此目的的污源搜罗卡塔尔

A obj = new A();
WeakReference wr = new WeakReference(obj);
obj = null;
//等待一段时间,obj对象就会被垃圾回收
...
if (wr.get()==null) {
  System.out.println("obj 已经被清除了 ");} else {
  System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
}

}

PhantomReference

追踪referent何时被enqueue到ReferenceQueue中,它唯风流倜傥的指标正是目的被回笼时能接受多个公告,用于追踪对象被垃圾回笼的景况,须求和援引队列ReferenceQueue类联合使用。

不提议接收,有秘密的内部存款和储蓄器败露危机,因为JVM不会自行扶植大家释放,大家务须求保障它指向的堆对象是不可达的

虚援用带给的内部存款和储蓄器败露危机参谋:java中虚引用PhantomReference与弱引用WeakReference(软引用SoftReference)的差异。

软引用和弱引用异样十分小,JVM都以先将其referent字段设置成null,之后将软引用或弱援引,参加到关系的援用队列中。大家得以认为JVM先回笼堆对象占用的内部存款和储蓄器,然后才将软援用或弱引用参预到引用队列。

而虚引用则分歧,JVM不会活动将虚援引的referent字段设置成null,而是先保留堆对象的内部存款和储蓄器空间,直接将PhantomReference参与到关系的引用队列,也正是说假设我们不手动调用PhantomReference.clear(卡塔尔(قطر‎,虚引用指向的堆对象内部存款和储蓄器是不会被放走的。

管理进度:

  • 不把referent设置为null.
  • PhantomReference援引过的heap对象管理到finalized状态,即调用了finalize(卡塔尔方法.
  • heap对象被假释此前把PhantomRefrence对象增加到它的ReferenceQueue中.

剪辑部分盖楼批评:
本身感到其实是这般,其实GC做的做事分为是两有的,第少年老成有的是将对象从finalizable状态到finalized状态,这只是到位了财富的放走;第二片段是reclaimed对象占用的内部存款和储蓄器。其实具有在ref中的三种reference的referent的靶子的reclaimed都唯有在相应reference对象的clear方法调用之后,技巧开展,所以,GC只是保障weakreference、softreference的clear方法被GC自动调用,并被加到referencequeue中,可是phantomreference对象在被投入到referencequeue中早先对象就曾经被GC finalied(如若定义了finalize方法的话,作者所指的finalized是指调用了finalize方法)了,只是还尚无开展第二步reclaimed,因为phantomreference对象的clear方法还一贯不被调用,所以不可能扩充reclaimed。

  Food food = new Food();
  PhantomReference<Food> phantomFood = new PhantomReference<Food>(food, new ReferenceQueue<Food>()); 
  food = null;

使用:

  • Object的finalize方法在回笼从前调用,若在finalize方法内成立此类的强援用会招致对象不恐怕回笼,恐怕引发JVM OutOfMemory
  • PhantomReference在finalize方法执行后展开回笼,防止上述难题

参考网页关于虚援引PhantomReference

@SuppressWarnings("static-access")
public static void main(String[] args) throws Exception {
    String abc = new String("abc");
    System.out.println(abc.getClass() + "@" + abc.hashCode());
    final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();
    new Thread() {
        public void run() {
            while (isRun) {
                Object obj = referenceQueue.poll();
                if (obj != null) {
                    try {
                        Field rereferent = Reference.class
                                .getDeclaredField("referent");
                        rereferent.setAccessible(true);
                        Object result = rereferent.get(obj);
                        System.out.println("gc will collect:"
                                + result.getClass() + "@"
                                + result.hashCode() + "\t"
                                + (String) result);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }.start();
    PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,
            referenceQueue);
    abc = null;
    Thread.currentThread().sleep(3000);
    System.gc();
    Thread.currentThread().sleep(3000);
    isRun = false;
}

WeakReference

参考

Java的内部存款和储蓄器回笼机制
Java中八个引用类SoftReference 、 WeakReference 和 PhantomReference的不相同
Java引用
引用
Java幽灵引用的坚守

ref =null;//去除对象的强引用

总结

  • 强引用指向的指标若是被引述,产生GC时是不会被回笼的,除非该目的没有被引述
  • 软援引在内部存款和储蓄器特别忐忑的时候会被回笼(无引用卡塔尔(قطر‎,别的时候不会被回笼,所以在行使在此以前要认清是还是不是为null进而剖断她是或不是业已被回笼了
  • 弱引用和虚援用指向的靶子(无援引卡塔尔在发出GC时一定会被回笼
  • 透过虚引用得不到引用的对象实例,虚援引的get(卡塔尔国方法长久重返null

SoftReference

科技世界 3

}

Java代码)

publicclassWeakTest{

publicstaticvoidmain(String[] args) {

留心,运营这几个程序供给用debug形式开展调解,在上头表明的地点加个断点。若是直白运维,结果很恐怕只是个null,用debug调节和测量检验的话会看出输出的是弱援用的地址。程序输出的sf结果和rq.poll(卡塔尔(قطر‎结果大器晚成致。

WeakReference sf =newWeakReference(ref,rq卡塔尔;//布局弱引用时传出ReferenceQueue

StrongReference