您的位置 首页 java

吃透Java基础十五:强引用、软引用、弱引用、虚引用

本文首发CSDN博客地址:

前言

在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。而对于如何描述一些“食之无味,弃之可惜”的对象就显得无能为力。我们希望能描述这样一类对象:当内存空间还足够时,则能保留在内存之中,如果内存在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。

在JDK1.2之后, Java 对引用的概念进行扩充,将引用分为强引用、软引用、弱引用、虚引用四种,这四种引用强度依次逐渐减弱。

强引用

我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。比如下面的object

 Object object = new Object();  

只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象。即使当内存空间不足, JVM 宁愿抛出OutOfMemoryError使程序终止,也不回收这种对象。

如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。比如ArraryList类的clear方法中就是通过将引用赋值为null来实现清理工作的:

吃透Java基础十五:强引用、软引用、弱引用、虚引用

在ArrayList类中定义了一个私有的变量elementData数组,在调用方法清空数组时可以看到为每个数组内容赋值为null。不同于elementData=null,强引用仍然存在,避免在后续调用 add()等方法添加元素时进行重新的内存分配。使用如clear()方法中释放内存的方法对数组中存放的引用类型特别适用,这样就可以及时释放内存。

软引用

软引用用来描述一些还有用,但并非必须的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中并进行第二次回收,如果这次回收还是没有足够的内存,才会抛出内存溢出异常。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现 缓存 :比如网页缓存、图片缓存等。

吃透Java基础十五:强引用、软引用、弱引用、虚引用

运行结果如下:

吃透Java基础十五:强引用、软引用、弱引用、虚引用

从上面的示例中就能看出,软引用关联的对象不会被GC回收。JVM在分配空间时,如果Heap空间不足,就会进行相应的GC,但是这次GC并不会收集软引用关联的对象,但是在JVM发现就算进行了一次回收后还是不足(Allocation Failure),JVM会尝试第二次GC,回收软引用关联的对象。

像这种如果内存充足,GC时就保留,内存不够,GC再来收集的功能很适合用在缓存的引用场景中。在使用缓存时有一个原则,如果缓存中有就从缓存获取,如果没有就从数据库中获取,缓存的存在是为了加快计算速度,如果因为缓存导致了内存不足进而整个程序崩溃,那就得不偿失了。

弱引用

弱引用也是用来描述非必须对象的,他的强度比软引用更弱一些,被弱引用关联的对象,在垃圾回收时,如果这个对象只被弱引用关联(没有任何强引用关联他),那么这个对象就会被回收。

吃透Java基础十五:强引用、软引用、弱引用、虚引用

运行输出:

吃透Java基础十五:强引用、软引用、弱引用、虚引用

从上面的代码中可以看出,弱引用关联的对象是否回收取决于这个对象有没有其他强引用指向它。这个确实很难理解,既然弱引用关联对象的存活周期和强引用差不多,那直接用强引用好了,干嘛费用弄出个弱引用呢?其实弱引用存在必然有他的应用场景。

weakHashMap类的设计:

设计 WeakHashMap类是为了解决一个有趣的问题。如果有一个值,对应的键已经不再 使用了, 将会出现什么情况呢? 假定对某个键的最后一次引用已经消亡,不再有任何途径引 用这个值的对象了。但是,由于在程序中的任何部分没有再出现这个键,所以,这个键 / 值 对无法从映射中删除。为什么垃圾回收器不能够删除它呢? 难道删除无用的对象不是垃圾回 收器的工作吗?

遗憾的是,事情没有这样简单。垃圾回收器跟踪活动的对象。只要映射对象是活动的, 其中的所有桶也是活动的, 它们不能被回收。因此,需要由程序负责从长期存活的映射表中 删除那些无用的值。 或者使用 WeakHashMap完成这件事情。当对键的唯一引用来自散列条目时, 这一数据结构将与垃圾回收器协同工作一起删除键 / 值对。

WeakHashMap 使用弱引用(weak references) 保存键。 WeakReference 对象将引用保存到另外一个对象中,在这里,就是散列键。对于这种类型的对象,垃圾回收器用一种特有的方式进行处理。通常,如果垃圾回收器发现某个特定的对象 已经没有他引用了,就将其回收。然而, 如果某个对象只能由 WeakReference 引用, 垃圾 回收器仍然回收它,但要将引用这个对象的弱引用放人队列中。WeakHashMap将周期性地检 查队列, 以便找出新添加的弱引用。一个弱引用进人队列意味着这个键不再被他人使用, 并 且已经被收集起来。于是, WeakHashMap将删除对应的条目。

除了WeakHashMap使用了弱引用, ThreadLocal 类中也是用了弱引用。

虚引用

虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象的实例,为一个对象设置虚引用关联的唯一目的就是希望能在这个对象被收集器回收时收到一个系统通知。在JDK1.2之后,提供了PhantomReference类来实现虚引用。

文章来源:智云一二三科技

文章标题:吃透Java基础十五:强引用、软引用、弱引用、虚引用

文章地址:https://www.zhihuclub.com/185004.shtml

关于作者: 智云科技

热门文章

网站地图