强软弱虚引用

介绍

作用

  1. 可以通过代码的方式决定某些对象的生命周期。
  2. 有利于JVM进行垃圾回收。

强引用

  对象的一般状态,初始化new出来的对象就是强引用。
  可达性分析算法中,根据GC Roots向下查找是用的就是强引用。


软引用

  软参考对象,由垃圾收集器根据内存需求自行清除。软引用通常用于实现内存敏感缓存。
假设垃圾收集器在某个时间点确定对象是softly reachable 。 那时候,它可能会选择原子地清除对该对象的所有软引用,以及对任何其他可轻松访问的对象的所有软引用,该对象可以通过一个强引用链来访问该对象。 在同一时间或稍后的时间,它将排入在引用队列中注册的新清除的软引用。

  在虚拟机抛出OutOfMemoryError之前,所有软引用对象可以保证被清除。 否则,在清除软引用的时间或者对一组对不同对象的引用将被清除的顺序没有约束。 但是,鼓励虚拟机实现偏离清除最近创建或最近使用的软参考。

  此类的直接实例可用于实现简单的缓存; 此类或派生子类也可用于较大的数据结构以实现更复杂的高速缓存。 只要软参考的指示是强有力的,即实际使用中,软参考将不会被清除。 因此,复杂的缓存可以例如阻止其最近使用的条目被丢弃,通过保持对这些条目的强烈的指示,使剩余的条目由垃圾收集器判断丢弃。

  用来描述一些有用但不是必须的对象,类似于生活总可有可无的物品,在java中使用java.lang.ref.SoftReference类来表示。
  对于软引用关联着的对象,只有在内存空间不足的时候,垃圾回收器才会回收这些对象。
  只要垃圾回收器没有回收掉,程序就可以使用它。
  软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。
  软引用可以用来实现内存敏感的高速缓存。当内存足够大时可以把数组存入软引用,取数据时就可从内存里取数据,提高运行效率。如浏览器的后退按钮。


弱引用

  弱参考对象,不会阻止其指定对象的最终确定,最终确定,然后被回收。弱引用最常用于实现规范化映射。

  假设垃圾收集器在某个时间点确定对象是weakly reachable 。 那时,它将原子地清除对该对象的所有弱引用,以及所有弱引用到任何其他弱可触及的对象,通过一连串强软引用可以从该对象到达该对象。 同时,它将声明所有以前弱可触及的对象都是可以确定的。 在同一时间或稍后的时间,它将排列在引用队列中注册的新清除的弱引用。

  弱引用也是描述非必须对象的。与软引用相比,弱引用具有更短暂的生命周期,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象,在Java中用java.lang.ref.WeakReference来表示。
  在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回 收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。


虚引用

  在收集者确定其指示物可能被回收之后排入队列的Phantom参考对象。幻像引用最常用于以比Java完成机制可能更灵活的方式安排事先清理操作。

  如果垃圾收集器在某个时间点确定幻像引用的引用是phantom reachable ,那么在那个时间或稍后的时间,它将引入引用。

  为了确保可回收对象保持原样,可能无法检索幻像引用的引用:虚幻引用的get方法始终返回null 。

  与软弱引用不同,幻像引用在垃圾收集器排入队列时不会自动清除。 通过幻影引用可访问的对象将一直保持到所有这样的引用被清除或者自身变得不可访问。

  虚引用主要用来跟踪对象被垃圾回收器回收的活动。
  与软弱引用不同,虚引用不影响对象的生命周期,虚引用必须和引用队列 (ReferenceQueue)联合使用。
  在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。
  当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。由于Object.finalize()方法的不安全性、低效性,常常使用虚引用完成对象回收前的资源释放工作。

  当GC一但发现了虚引用对象,将会将PhantomReference对象插入ReferenceQueue队列. * 而此时PhantomReference所指向的对象并没有被GC回收,而是要等到ReferenceQueue被你真正的处理后才会被回收。

  当JVM将虚引用插入到引用队列的时候,虚引用执行的对象内存还是存在的。但是PhantomReference并没有暴露API返回对象。所以如果我想做清理工作,需要继承PhantomReference类,以便访问它指向的对象。如NIO直接内存的自动回收,就使用到了sun.misc.Cleaner。


总结

引用类型被回收时间用途生存时间
强引用从来不会对象的一般状态jvm停止运行时
软引用内存不足时对象缓存内存不足时
弱引用jvm垃圾回收时对象缓存gc后
虚引用不知不知不知

  利用软引用和弱引用可以解决OOM的问题。

利用软引用和弱引用解决OOM问题: 假如有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出,此时使用软引用可以解决这个问题。

设计思路是: 用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。