软引用、弱引用和虚引用

强引用

强引用(strong reference)是使用最普遍的引用,如果一个对象具有强引用,那垃圾回收器绝不会回收它,例如Object obj = new Object();,即使当内存空间不足时,JVM宁愿抛出OOM,也不会回收具有强引用的对象来解决内存不足的问题。

我们可以显示的设置对象为null,或者跳出对象的生命周期范围,让垃圾收集器将其判定为不存在引用,是个可以被回收的对象,例如obj = null;

全局对象:手动的将对象赋值为null,最典型的全局对象设置为null的就是在ArrayList的clear()方法中,对于类中的全局变量elementData来说,仅仅的将其置为null是不可行的,因为数组中的对象还是会继续引用的,所以此时需要将数组中每个位置的对象全部置为null,也就是将所有的对象的引用都释放掉,这样才会被GC回收。

/**
 * Removes all of the elements from this list.  The list will
 * be empty after this call returns.
 */
public void clear() {
  modCount++;

  // clear to let GC do its work
  for (int i = 0; i < size; i++)
    elementData[i] = null;

  size = 0;
}

局部变量:一般情况下,一个对象保存在堆中,对象的引用保存在Java栈中,由于栈是线程私有的,所以当线程结束时,Java栈被自动回收,这时堆中对象的引用数-1,直到引用数变为0后,可以被GC回收。例如:

public void method() {
  Object obj = new Object();
}

我们通过new创建的对象一般都是强引用

弱引用

弱引用(weak reference)是可以被GC强制回收的,当垃圾收集器发现一个存活的弱可达对象时,就会将其放入响应的ReferenceQueue中,之后可能会遍历这个ReferenceQueue并执行响应的清理,弱可达对象是指该对象的引用只剩下弱引用。

我们可以通过弱引用的get()方法给对象赋值给新的强引用,在回收前,GC会再次判断该对象是否可以安全回收。所以,弱引用的对象的回收过程可以横跨多个GC周期,在Java中可以使用WeakReference类创建一个弱引用对象。例如:

public static void main(String[] args) throws Exception {
  String cc = new String("串串");
  // 创建对象cc的弱引用
  WeakReference<String> cc_wr = new WeakReference<>(cc);

  // ① cc = null;
  // ② System.gc();
  // 为对象cc创建一个强引用,若对象cc已经被回收,则返回null
  String cc_s = cc_wr.get();
  // ③ cc = null;
  System.out.println(cc_s);
}

分析

  1. 仅开启①

    image-20200530000738739

    弱引用对象尚未被回收

  2. 仅开启②

    image-20200530001335758

  3. 仅开启③

    image-20200530001504957

  4. 开启①②

    image-20200530001545556

    哇啊哦~对象被回收了,这是因为我们先将对象的弱引用断开,然后又手动进行了一次gc,把对象给回收了

  5. 开启②③

    image-20200530002013851

  6. 开启①②③

    image-20200530002029511

软引用

软引用(Soft Reference)是比弱引用更难被垃圾回收器回收的对象,什么时候回收软引用完全由JVM自己决定,一般只会在即将OOM时才会回收软引用,算是JVM内存管理最后的倔强。这就意味着可能会有非常频繁的Full GC,STW时间也变长,因为老年代中的存活对象多了。

public static void main(String[] args) throws Exception {
  SoftReference<String> cc_sr = new SoftReference<>(new String("串串"));
  System.out.println(cc_sr.get());
}

虚引用

虚引用和弱引用、软引用不同,它并不影响对象的生命周期,使用java.lang.ref.PhantomReference类表示,和弱引用、软引用不同的是,虚引用必须和引用队列关联使用,当GC准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用放进与之关联的引用队列中。

为了防止可回收对象的残留,虚引用对象不应该被获取,PhantomReference的get()方法始终返回null,虚引用不会被GC自动清除,因为它们被存放到队列中,通过虚引用可达的对象会继续留在内存中,直到调用此引用的clear()方法,或者引用自身变为不可达。

也就是说我们如果不手动调用clear()方法来清除虚引用,则非常可能造成OOM而导致JVM宕机。

public static void main(String[] args) throws Exception {
  ReferenceQueue<String> rq = new ReferenceQueue<>();
  PhantomReference<String> cc_p = new PhantomReference<>(new String("cc"), rq);
  System.out.println(cc_p.get());
}

可以使用JVM参数-XX:+PrintReferenceGC查看各类引用对GC的影响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值