JVM | 垃圾回收策略(三)

600 阅读4分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

本文承接上篇文章《JVM | 垃圾回收策略(二)》,继续讲JVM中引用类型分类。

3.3引用类型分类

4e90a6f9e5b491fc93f7650f1aecf3be.jpg

我们知道Java创建一个对象可以采用new的方式,如下图所示。

final Object obj = new Object();

那么变量obj指向创建的对象,这种引用方式是什么类型的呢?答案是强引用。

强引用(Strong Reference) ,引用方式如上面的代码所示,只要强引用在,永远不会回收被引用的对象。哪怕是出现内存溢出,也不会回收这些对象。这样引用对象的方式,除非对象没有任何路径链接到根对象,否则对象是不会被GC的。

那么强引用的对象是否手动回收呢?

#这是一种最简单的方式
obj = null;

所以Java语言又提供了软引用(SoftReference) ,它用来描述一些有用但非必须的对象,较之于强引用,软件引用关联的对象,只有在内存不足的时候JVM才会回收这些对象,创建方式如下。

SoftReference<String> ref = new SofteReferencec<>("value");

那么软引用能使用在哪些场景呢,之前我们有一篇文章讲到了,可以使用软引用实现一个简易的基于内存的缓存实现。

AtomicReference<SoftReference<List<<String>>> = new AAtomicReference();

这种缓存可以临时存储一些有用但并不是必须的对象,SoftReference确保当内存出现不足的时候,可以被正常回收,AtomicReference保证了并发环境下的读写安全。比如可以用于

  • 接口Mock
  • 网页缓存
  • 图片缓存。

软引用的特点是在内存不足的情况下会被回收,那么有没有只要发生GC,被引用的对象都会被回收呢?

当然,Java语言提供了弱引用(Weak Reference) ,弱引用的对象就是只要JVM垃圾回收器发现了它,它就会被无情地收割,回收。弱引用是用来描述非必须的对象,其创建方式如下。

WeakReference<String> ref = new WeakRefence<>("value");

弱引用适应的场景是用于内存比较敏感的缓存。比如java.util.WeakHashMap中的key就是使用弱引用。

讲到这,需要引入一个重要的引用队列ReferenceQueue,我们在使用SoftReferenceWeakReference的时候,除了上面讲到的用法,我们还有另一种是使用方式。

WeakReference(T referent, ReferenceQueue<? super T> q)

即传入一个引用队列,这个队列的作用是当垃圾回收器准备回收一个被引用的对象时,该引用会被加入到关联的ReferenceQueue。程序可以通过判断引用队列中是否已经加入引用,来了解被引用的对象是否被GC回收。

对于SoftReferenceWeakReference,使用引用队列我们只能在对象回收之后在引用队列查看对象是否被回收,那么有没有一种方式,在对象回收之前,收到一个通知,去做一些相应对的处理呢?

当然,Java语言提供了虚引用(Phantom Reference) ,有时我们也称之为幽灵引用。虚引用并不影响对象的生命周期,如果一个对象只有虚引用,那么它就和没有任何引用一样,在任何对象时候都可能被垃圾回收器回收。创建方式如下。

ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> ref = new PhantomReference<>("value",queue);

那么要它有何用呢?虚引用主要是用来跟踪对象被垃圾回收器回收的活动,说的直白一点,就是观察对象是否要被垃圾回收器回收了,如果确实要被回收,那么就能收到一个系统通知。

相较于其它的引用方式,虚引用必须要和引用队列配合使用,并且我们无法通过虚引用来获取对一个对象的真实引用

当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中,程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将会被垃圾回收器回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

比如采取以下的方式进行判断虚引用是否已经被加入到引用队列。

while (true) {
   Reference poll = queue.poll();//引用队列
   if (poll != null) {
   System.out.println("虚引用被回收了:" + poll);
   }
}

没看够,请跳转到下一篇文章JVM | 垃圾回收策略(三)