Java的四种引用——强引用、弱引用、软引用、虚引用

众所周知,Java是有四种引用的,分别是:强引用、弱引用、软引用、虚引用。

为了学习这些引用之间的区别和联系,写下这篇博客。

参考自此博客

强引用

我们平时用到的最普遍的引用,就是强引用。如果一个对象具有强引用,GC就不会回收它。

比如下面就是一个强引用

Object o = new Object();	// 强引用

当我们内存不足时,Java虚拟机宁愿抛出OutOfMemoryError异常也不愿意回收具有强引用的对象。

因此,当我们不使用一个对象时,应该用如下方式来弱化引用,帮助GC回收

o = null;		// 帮助GC回收这个对象

当我们显式地设置o为null,或者超出了对象的生命周期范围,GC会认为该对象不存在引用,这时就可以回收这个对象。但要注意的是,不一定是马上回收!具体何时回收取决于GC的算法。

比如我们下面的例子

public void function(){
    Object o = new Object();
}

我们在方法中有一个强引用,它保存在栈中。而真正new出来的对象则保存在堆中。当方法结束,强引用的生命周期结束,此时引用不再存在,这个对象就会被回收。

当o为全局变量时,我们就需要在使用结束后将它置为null,来辅助GC对其进行回收。

比如ArrayList的源码中,就有一个clear函数来辅助GC回收它内部的数据

private transient Object[] elementData;
...
public void clear() {
        modCount++;
        // Let gc do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        size = 0;
}

可以看到,它内部执行的操作就是把所有元素全部置为null,而不是仅仅把elementData置为null。如果仅仅把elementData置为null,强引用会依然存在。

当面对数组元素时,采用这样的方法可以及时释放它的内存。

软引用

采用软引用,当内存空间足够的时候,GC不会回收它。而内存空间不足时,GC就会回收这些对象。只要不被回收,就可以继续使用。

 Integer num = new Integer(1);                                     		// 强引用
 SoftReference<Integer> softRef = new SoftReference<Integer>(num);     	// 软引用

软引用在实际的使用场景中十分重要,比如我们浏览器的后退按钮。当我们按下后退键时,加载前一个网页有两种策略

  1. 从缓存中重新取出

  2. 重新进行请求加载

如果我们仅仅采用第一种策略,会造成大量的内存浪费,甚至内存溢出。

如果我们仅仅采用第二种策略,会浪费网络资源,并且加载缓慢。

此时,我们就可以使用软引用来存放。

Browser prev = new Browser();               
SoftReference ref = new SoftReference(prev); 	
if(ref.get()!=null){ 
	rev = (Browser) ref.get();          
}else{
	prev = new Browser();               
	ref = new SoftReference(prev);       
}

弱引用

弱引用与软引用的区别在于:只具有弱引用的对象的生命周期更加短暂。

在GC线程扫描它所的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

String str=new String("abc");    
WeakReference<String> abcWeakRef = new WeakReference<String>(str);
str=null; 

如果这个对象偶尔使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么应该用 Weak Reference 来存储此对象。

虚引用

虚引用和其他几种引用都不同,它是形同虚设的,并不会决定对象的声明周期。如果一个对象仅仅只有虚引用,和它没有引用是一样的,随时会被GC回收。

使用虚引用主要用于追踪对象被回收的过程。

总结

可以用下表来总结本篇文章

引用类型被垃圾回收时间用途生存时间
强引用从来不会对象的一般状态JVM停止运行时终止
软引用在内存不足时对象缓存内存不足时终止
弱引用在垃圾回收时对象缓存gc运行后终止
虚引用UnknownUnknownUnknown
### Java强引用弱引用的区别 #### 强引用 (Strong Reference) 强引用是最常见的引用类型,在Java中,通过简单的赋值操作即可创建强引用。只要存在强引用指向某个对象,则该对象就不会被垃圾回收机制所回收。 ```java Object obj = new Object(); ``` 上述代码片段展示了如何创建一个强引用实例[^1]。当程序不再需要此对象时,应显式解除引用或将变量设置为`null`以便让垃圾收集器能够回收资源。 #### 弱引用 (Weak Reference) 相比之下,弱引用是一种较形式的引用关系,它不会阻止目标对象成为垃圾回收的目标。即使当前内存空间充足,一旦触发GC周期,持有弱引用的对象也会被清理掉。为了实现这一点,可以利用`java.lang.ref.WeakReference<T>`类来构建弱引用: ```java import java.lang.ref.WeakReference; String str1 = new String("abc"); WeakReference<String> weakRefStr = new WeakReference<>(str1); ``` 这段代码说明了怎样定义并初始化一个字符串类型的弱引用实例[^2]。值得注意的是,由于弱引用不具备保持对象存活的能力,因此通常会配合`ReferenceQueue`一起使用,从而更好地管理这些即将消失的对象状态变化事件。 #### 主要差异对比 | 特征/属性 | 强引用 | 弱引用 | | --- | --- | --- | | 对象生命周期影响 | 阻碍垃圾回收;只有当所有强引用都被移除后才会考虑回收 | 不阻碍垃圾回收;每次GC都可能被清除 | | 创建方式 | `T t = new T();` 或者其他常规赋值表达式 | 使用`new WeakReference<>(referent)`构造函数 | | 应用场景 | 大多数情况下默认使用的引用模式 | 缓存数据结构、监听器列表等不需要长期存在的场合 | #### 实际应用案例分析 对于缓存设计而言,如果希望某些条目能够在必要时刻自动释放其所占用的空间而不必手动干预的话,那么采用弱引用来保存键值对就是一种合理的选择。因为每当发生GC动作的时候,那些仅由弱引用维持着联系的数据项将会自然地被淘汰出局,进而达到节省内存的目的[^3]。 另一方面,考虑到性能因素以及潜在的风险——即频繁发生的GC可能导致大量不必要的对象销毁活动——开发者应当谨慎评估具体需求后再决定是否引入此类特性到项目当中去[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值