0%

对象的引用

对象的引用

对象的引用分为了四个级别,从高到低为强引用软引用弱引用虚引用

引用类型都是java.lang.ref.Reference类的子类

为什么引用需要分级别

为了使得在内存空间足够的时候,可以将对象保留在内存中;当内存空间在进行垃圾回收之后还是很紧张时,可以抛弃这些对象

强引用(StrongReference)

最普遍的引用,如果一个对象具有强引用,就类似于生活必需品,垃圾收集器绝对不会回收它,当内存空间不足,java虚拟机宁愿抛出OutOfMemeryError错误,使程序异常终止,也不会随意回收具有强引用的对象来解决内存不足的问题

当使用new来实例化一个对象并将其赋给一个变量的时候,这个变量就成为了指向这个对象的引用

1
User user = new User();

无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉该对象

特点

  • 强引用可以直接访问目标对象
  • 强引用所指向的对象在任何时候都不会被系统回收,虚拟机宁愿抛出OOM异常,也不会回收强引用所指向的对象
  • 强引用可能会导致内存泄漏

软引用(SoftReference)

一个对象具有软引用,类似于可有可无的生活用品。如果内存空间足够,垃圾收集器就不会回收它,如果空间内存不足,在发生内存溢出之前,会将这些对象列入回收范围内,可以用软引用来实现内存敏感的高速缓存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
TestRef obj = new TestRef();
obj.setName("张三");
// 创建软引用,此时ref是通过软引用指向的obj对象
SoftReference<TestRef> ref = new SoftReference<>(obj);
System.out.println(obj);
// 清除强引用,如果不清除强引用的话,添加其他引用类型是没有作用的
obj = null;
// 进行垃圾回收
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// ref的get()方法可以获取到所引用的实际对象
if(ref.get() != null){
System.out.println(ref.get());
System.out.println(Objects.requireNonNull(ref.get()).getName());
// 清除引用
ref.clear();
// 此时为null
System.out.println(ref.get());

}


com.zhanghe.study.ref.TestRef@66d3c617
com.zhanghe.study.ref.TestRef@66d3c617
张三
null

可以和引用队列联合使用,如果软引用所引用的对象被垃圾回收,java虚拟机会将这个软引用加入到与之关联的引用队列中

弱引用(WeakReference)

一个对象具有弱引用,也类似于可有可无的生活用品。弱引用和软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期,只能存活到下一次垃圾回收之前。在垃圾收集器线程扫描内存区域时,一旦发现了只具有弱引用的对象,不管当前内存是否足够,都会进行回收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
TestRef obj = new TestRef();
obj.setName("张三");
// 创建弱引用,此时ref是通过弱引用指向的obj对象
WeakReference<TestRef> ref = new WeakReference<>(obj);
System.out.println(obj);
// 清除强引用,如果不清除强引用的话,添加其他引用类型是没有作用的
obj = null;
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// ref的get()方法可以获取到所引用的实际对象
if(ref.get() != null){
System.out.println(ref.get());
System.out.println(Objects.requireNonNull(ref.get()).getName());
// 清除引用
ref.clear();
System.out.println(ref.get());

} else {
System.out.println("弱引用已经被回收了");
}

com.zhanghe.study.ref.TestRef@66d3c617
弱引用已经被回收了

可以和引用队列联合使用,如果弱引用所引用的对象被垃圾回收,java虚拟机会将这个弱引用加入到与之关联的引用队列中

虚引用(PhantomReference)

虚引用,顾名思义,就是形同虚设,与前面的几个都不相同,虚引用不会决定对象的生命周期,也无法通过虚引用来取得一个对象实例。如果一个对象仅持有虚引用,就和没有任何引用一样,任何时候都可以被垃圾回收器回收,其唯一的作用就是可以在这个对象被收集器回收时收到一个系统通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
TestRef obj = new TestRef();
obj.setName("张三");
ReferenceQueue<TestRef> phantomQueue = new ReferenceQueue<>();
// 创建虚引用,此时ref是通过虚引用指向的obj对象
// 虚引用必须要和引用队列一起使用,只存在public PhantomReference(T referent, ReferenceQueue<? super T> q)一种构造器
PhantomReference<TestRef> ref = new PhantomReference<>(obj,phantomQueue);
System.out.println(obj);

// ref的get()方法可以获取到所引用的实际对象
if(ref.get() != null){
System.out.println(ref.get());
System.out.println(Objects.requireNonNull(ref.get()).getName());
// 清除引用
ref.clear();
System.out.println(ref.get());

} else {
System.out.println("虚引用已经被回收了");
}



// 输出结果
//com.zhanghe.study.ref.TestRef@66d3c617
//虚引用已经被回收了

虚引用主要用于跟踪对象被垃圾回收的活动。虚引用与弱引用的区别在于,虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器回收一个对象时,如果发现它有虚引用,在回收对象之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过引用队列中是否加入了虚引用,来了解被引用的对象是否将要被垃圾回收。

欢迎关注我的其它发布渠道