Java中的 WeakReference 和 SoftReference

本文深入探讨Java中的引用类型,包括强引用、弱引用、软引用等,并通过代码示例展示了不同引用类型的特性和应用场景。
我们知道Java语言中没有指针,取而代之的是引用reference。Java中的引用又可以分为四种:强引用,弱引用(WeakReference),软引用(SoftReference),虚引用(PhantomReference)。其中强引用,就是我们平时使用的最多的最普通的引用,虚引用一般我们是没有机会使用到的。所以我们主要了解下 WeakReference 和 SoftReference(除了上面说的四种引用之外,其实还有一种引用——原子引用AtomicReference,用于并发编程环境)。


1. 先上一段代码:


复制代码
public class ReferenceTest {
    public static void main(String[] args){
        LinkedList<byte[]> list = new LinkedList<>();
        for(int i=0; i<1024; i++){
            list.add(new byte[1024*1024]);
        }
    }
}
复制代码
上面的代码会抛出:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space


堆内存溢出。因为我们不断的在堆上分配一个 1M 大小的 byte[]对象,并且将该引用加入到 list 中,循环1024次,需要占用 1G 的堆内存,从而导致 heap space OutOfMemory.


2. 我们使用 WeekReference 对代码进行修改:


复制代码
public class ReferenceTest {
    public static void main(String[] args) {
        long beginTime = System.nanoTime();
        LinkedList<WeakReference<byte[]>> list = new LinkedList<>();
        for (int i = 0; i < 1024; i++) {
            list.add(new WeakReference<>(new byte[1024 * 1024]));
        }
        long endTime = System.nanoTime();
        System.out.println(endTime - beginTime);
    }
}
复制代码
输出的结果:195947704 (0.19秒)


我们发现堆内存溢出的错误没有了。这是什么原因呢。因为我们使用了 弱引用WeekReference 来引用堆上的 1M 的byte[]对象,而弱引用WeekReference引用的对象,如果仅仅只被弱引用,而没有被强引用的话,在下一次GC时,就会回收该对象占用的内存,所以不会内存溢出。


3. 我们使用 SoftReference 对代码进行修改:


复制代码
public class ReferenceTest {
    public static void main(String[] args) {
        long beginTime = System.nanoTime();
        LinkedList<SoftReference<byte[]>> list = new LinkedList<>();
        for (int i = 0; i < 1024; i++) {
            list.add(new SoftReference<>(new byte[1024 * 1024]));
        }
        long endTime = System.nanoTime();
        System.out.println(endTime - beginTime);
    }
}
复制代码
输出结果:1499904286 (1.5秒)


我们发现堆内存溢出的错误也没有了。因为我们使用了 软引用SoftReference 来引用堆上的 1M 的byte[]对象,而软引用SoftReference引用的对象,如果仅仅只被软引用,而没有被强引用的话,在内存空间不足时,GC 就会回收该对象占用的内存,所以不会内存溢出。


但是我们注意到 采用WeekReference和采用SoftReference所花费的时间,有接近10被的差距。原因应该是,SoftReference只有在内存空间不足时,GC才会回收对象占用的空间,而这时进行的是 full GC,full GC会导致 STW 程序暂停,所以花费的时间过多。


4. 总结


强引用:只要堆上的对象,被至少一个强引用所指向,那么GC就不会回收该对象的内存空间。


弱引用:只要堆上的对象仅仅只被弱引用所指向,不管当前内存空间是否足够,下次GC都会回收对象的内存空间。


软引用:只要堆上的对象仅仅只被软引用所指向,并且当内存空间不足时,GC才会回收对象的内存空间。


WeakReference 和 SoftReference一般使用在构造一个缓存系统,比如使用一个map来构造。因为缓存系统是一个“全生命期”的对象,系统停止,缓存对象才会被销毁,所以当我们不断的想缓存对象中添加对象时,那么就会导致该缓存对象map所引用的对象越来越多,而因为是强引用,这些被放进map缓存了的对象不能被GC锁回收,那么就导致系统堆内存占用会越来越大,从而最终导致内存溢出。


那么此时我们就可以使用 WeakReference 或 SoftReference了,将强引用通过WeakReference 和 SoftReference 包装之后,变成弱引用和软引用,那么当缓存中的对象,仅仅被缓存map锁引用时,那么分别在下次GC和内存不足GC时就会回收这些对象占用的内存。其实JDK给我们提供了一个专门的类:WeakHashMap ,弱引用的hashMap,所以构造缓存系统是,我们可以考虑使用它。


其实这里引出了另外一个问题,jdk中众多的map,我们应该如何进行选择:


HashMap


ConcurrentHashMap


TreeMap


WeakHashMap


LinkedHashMap


Collections.synchronizedMap


Hashtable


等等。我们在选择一个map时,应该好好的考虑下,那个更加适合我们的需求。
【语音分离】基于平均谐波结构建模的无监督单声道音乐声源分离(Matlab代码实现)内容概要:本文介绍了基于平均谐波结构建模的无监督单声道音乐声源分离方法,并提供了相应的Matlab代码实现。该方法通过对音乐信号中的谐波结构进行建模,利用音源间的频率特征差异,实现对混合音频中不同乐器或人声成分的有效分离。整个过程无需标注数据,属于无监督学习范畴,适用于单通道录音场景下的语音与音乐分离任务。文中强调了算法的可复现性,并附带完整的仿真资源链接,便于读者学习与验证。; 适合人群:具备一定信号处理基础Matlab编程能力的高校学生、科研人员及从事音频处理、语音识别等相关领域的工程师;尤其适合希望深入理解声源分离原理并进行算法仿真实践的研究者。; 使用场景及目标:①用于音乐音频中人声与伴奏的分离,或不同乐器之间的分离;②支持无监督条件下的语音处理研究,推动盲源分离技术的发展;③作为学术论文复现、课程项目开发或科研原型验证的技术参考。; 阅读建议:建议读者结合提供的Matlab代码与网盘资料同步运行调试,重点关注谐波建模与频谱分解的实现细节,同时可扩展学习盲源分离中的其他方法如独立成分分析(ICA)或非负矩阵分解(NMF),以加深对音频信号分离机制的理解。
内容概要:本文系统介绍了新能源汽车领域智能底盘技术的发展背景、演进历程、核心技术架构及创新形态。文章指出智能底盘作为智能汽车的核心执行层,通过线控化(X-By-Wire)域控化实现驱动、制动、转向、悬架的精准主动控制,支撑高阶智能驾驶落地。技术发展历经机械、机电混合到智能三个阶段,当前以线控转向、线控制动、域控制器等为核心,并辅以传感器、车规级芯片、功能安全等配套技术。文中还重点探讨了“智能滑板底盘”这一创新形态,强调其高度集成化、模块化优势及其在成本、灵活性、空间利用等方面的潜力。最后通过“2025智能底盘先锋计划”的实车测试案例,展示了智能底盘在真实场景中的安全与性能表现,推动技术从研发走向市场验证。; 适合人群:汽车电子工程师、智能汽车研发人员、新能源汽车领域技术人员及对智能底盘技术感兴趣的从业者;具备一定汽车工程或控制系统基础知识的专业人士。; 使用场景及目标:①深入了解智能底盘的技术演进路径与系统架构;②掌握线控技术、域控制器、滑板底盘等关键技术原理与应用场景;③为智能汽车底盘研发、系统集成与技术创新提供理论支持与实践参考。; 阅读建议:建议结合实际车型技术标准进行延伸学习,关注政策导向与行业测试动态,注重理论与实车验证相结合,全面理解智能底盘从技术构想到商业化落地的全过程。
【顶级EI复现】计及连锁故障传播路径的电力系统 N-k 多阶段双层优化及故障场景筛选模型(Matlab代码实现)内容概要:本文介绍了名为《【顶级EI复现】计及连锁故障传播路径的电力系统 N-k 多阶段双层优化及故障场景筛选模型(Matlab代码实现)》的技术资源,重点围绕电力系统中连锁故障的传播路径展开研究,提出了一种N-k多阶段双层优化模型,并结合故障场景筛选方法,用于提升电力系统在复杂故障条件下的安全性与鲁棒性。该模型通过Matlab代码实现,具备较强的工程应用价值学术参考意义,适用于电力系统风险评估、脆弱性分析及预防控制策略设计等场景。文中还列举了大量相关的科研技术支持方向,涵盖智能优化算法、机器学习、路径规划、信号处理、电力系统管理等多个领域,展示了广泛的仿真与复现能力。; 适合人群:具备电力系统、自动化、电气工程等相关背景,熟悉Matlab编程,有一定科研基础的研究生、高校教师及工程技术人员。; 使用场景及目标:①用于电力系统连锁故障建模与风险评估研究;②支撑高水平论文(如EI/SCI)的模型复现与算法验证;③为电网安全分析、故障传播防控提供优化决策工具;④结合YALMIP等工具进行数学规划求解,提升科研效率。; 阅读建议:建议读者结合提供的网盘资源,下载完整代码与案例进行实践操作,重点关注双层优化结构与场景筛选逻辑的设计思路,同时可参考文档中提及的其他复现案例拓展研究视野。
<think>我们正在讨论Java中的WeakReferenceSoftReference的区别及使用场景。首先,我们需要明确这两个类都属于Java的引用类型,它们位于java.lang.ref包中,用于帮助管理内存,避免内存溢出。主要区别在于垃圾回收器(GC)对待它们的方式:1.WeakReference(弱引用):当垃圾回收器进行回收时,无论内存是否充足,都会回收被弱引用指向的对象。也就是说,只要对象只被弱引用指向,那么在下一次垃圾回收时,这个对象就会被回收。2.SoftReference(软引用):当垃圾回收器进行回收时,只有在内存不足的情况下,才会回收被软引用指向的对象。因此,软引用可以用来实现内存敏感的缓存,当内存足够时,缓存对象可以保留;当内存不足时,这些对象可以被回收,从而避免内存溢出。使用场景:-WeakReference的典型使用场景是在实现规范化映射(比如WeakHashMap)时,它不会阻止键值被垃圾回收。另外,在需要不影响垃圾回收的情况下监听对象(例如某些监听器)时也很有用。-SoftReference常用于缓存,尤其是当缓存的对象比较大,而且我们希望在不影响应用性能的前提下,在内存不足时自动清理缓存。下面我们通过代码示例来进一步说明:```javaimportjava.lang.ref.WeakReference;importjava.lang.ref.SoftReference;publicclassReferenceExample{publicstaticvoidmain(String[]args){//创建一个对象StringstrongRef=newString("Hello,World!");//创建一个弱引用,指向该对象WeakReference<String>weakRef=newWeakReference<>(strongRef);//创建一个软引用,指向该对象SoftReference<String>softRef=newSoftReference<>(strongRef);//取消强引用strongRef=null;//强制触发垃圾回收(注意:这只是建议,不能保证立即执行)System.gc();//检查弱引用:很可能已经被回收System.out.println("WeakReference:"+weakRef.get());//检查软引用:由于内存充足,可能还未被回收System.out.println("SoftReference:"+softRef.get());}}```注意:在实际运行中,垃圾回收的行为可能会因为JVM的实现当前内存状况而有所不同。上面的代码中,我们取消了强引用后,弱引用指向的对象在垃圾回收时被回收的概率很大,而软引用指向的对象在内存充足时可能不会被回收。另外,Java还提供了PhantomReference(虚引用)ReferenceQueue(引用队列),它们可以用于更复杂的场景,比如在对象被回收时收到通知执行清理操作。总结:-WeakReference:垃圾回收时立即回收(只要没有强引用),用于避免阻止垃圾回收的场景。-SoftReference:在内存不足时回收,用于实现缓存。相关问题:1.什么是Java的强引用?2.如何结合ReferenceQueue使用WeakReferenceSoftReference?3.在Android开发中,SoftReferenceWeakReference的使用有什么不同?4.使用WeakHashMap有什么注意事项?5.如何通过软引用实现一个简单的缓存?</think>### JavaWeakReferenceSoftReference的区别及使用场景 #### 核心区别 1. **垃圾回收行为** - **软引用(SoftReference)**:仅在内存不足时被回收(JVM抛出`OutOfMemoryError`前) 垃圾回收逻辑:`可用内存 < 当前堆大小 * -Xmx比例`(默认70%)时触发回收[^1] - **弱引用(WeakReference)**:**无论内存是否充足**,只要发生GC就会被回收 $$ \text{回收条件}:\ \text{GC触发} \ \land \ \neg \exists \ \text{强引用} $$ 2. **引用强度排序** $$ \text{强引用} > \text{软引用} > \text{弱引用} > \text{虚引用} $$ - 强引用:`Object obj = new Object()` - 弱引用:`WeakReference<Object> ref = new WeakReference<>(obj)` 3. **典型使用场景** | 引用类型 | 适用场景 | 示例 | |----------------|-----------------------------------|--------------------------| | **SoftReference** | 内存敏感缓存 | 图片缓存、临时计算结果 | | **WeakReference** | 防止内存泄漏的辅助数据结构 | `WeakHashMap`键引用、监听器 | #### 代码示例对比 ```java // 软引用示例:缓存实现 SoftReference<BigData> cache = new SoftReference<>(loadBigData()); if (cache.get() != null) { // 内存充足时可用 process(cache.get()); } else { // 内存不足时自动清除 reloadCache(); } // 弱引用示例:防止内存泄漏 WeakReference<EventListener> listenerRef = new WeakReference<>(new EventListener()); eventBus.register(listenerRef.get()); // GC后自动解除绑定 ``` #### 引用队列(ReferenceQueue)机制 ```mermaid graph LR A[对象被回收] --> B[引用入队] B --> C[执行清理操作] ``` 典型应用: ```java ReferenceQueue<Object> queue = new ReferenceQueue<>(); WeakReference<Object> ref = new WeakReference<>(new Object(), queue); // 监控回收状态 Reference<?> clearedRef = queue.remove(); // 阻塞直到有引用入队 System.out.println("对象已被回收: " + clearedRef); ``` #### 关键注意事项 1. **软引用可能导致缓存雪崩** 内存不足时集中回收所有软引用对象,需设计回源机制 2. **弱引用不保证存活时间** 对象可能在任何GC周期被回收,需做空值检查 3. **Android系统差异** Android 2.3+ 中软引用回收策略更激进(优先于弱引用回收)[^2] > 实践建议:优先考虑`WeakHashMap`或`ConcurrentHashMap`+弱引用方案,而非直接使用`SoftReference`实现缓存[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值