SoftReference

本文深入探讨了Java中的SoftReference概念,解释了其在内存敏感程序中的应用,包括如何创建SoftReference、如何利用SoftReference进行缓存管理以及SoftReference的内部实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SoftReference的语义就是当内存不够用的时候,GC会回收SoftReference所引用的对象。所以,在memory sensitive的程序中将某些大型数据设置成SoftReference再合适不过了。

创建一个SoftReference:

Object obj = new Object();
SoftReference softRef = new SoftReference(obj);     
obj = null; 

最后那句“obj = null”很重要。如果不将obj设置成null,那么new出来的Object就会有一个"strong reference",如果这样,softRef就不能发挥作用了。

使用SoftReferene:

Object obj2;     
obj2 = sr.get();     
if (obj2 == null) // GC freed this     
      sr = new SoftReference(obj2 = new Object());  

 因为是SoftReference,所以有可能已经被GC回收了,所以需要判断sr.get()的返回值是否为null。如果是的话,就再重新new一个Object。这里的最后一行代码也很有讲究,比如,也许会这么写:

Object obj2;     
obj2 = sr.get();     
if (obj2 == null) {     
    sr = new SoftReference(new Object());     
    obj2 = sr.get();     
}   

SoftReference源码:

/**
 * @(#)SoftReference.java	1.36 09/02/26
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.lang.ref;


/***
 * Soft reference objects, which are cleared at the discretion of the garbage
 * collector in response to memory demand.  Soft references are most often used
 * to implement memory-sensitive caches.
 *
 * <p> Suppose that the garbage collector determines at a certain point in time
 * that an object is <a href="package-summary.html#reachability">softly
 * reachable</a>.  At that time it may choose to clear atomically all soft
 * references to that object and all soft references to any other
 * softly-reachable objects from which that object is reachable through a chain
 * of strong references.  At the same time or at some later time it will
 * enqueue those newly-cleared soft references that are registered with
 * reference queues.
 *
 * <p> All soft references to softly-reachable objects are guaranteed to have
 * been cleared before the virtual machine throws an
 * <code>OutOfMemoryError</code>.  Otherwise no constraints are placed upon the
 * time at which a soft reference will be cleared or the order in which a set
 * of such references to different objects will be cleared.  Virtual machine
 * implementations are, however, encouraged to bias against clearing
 * recently-created or recently-used soft references.
 *
 * <p> Direct instances of this class may be used to implement simple caches;
 * this class or derived subclasses may also be used in larger data structures
 * to implement more sophisticated caches.  As long as the referent of a soft
 * reference is strongly reachable, that is, is actually in use, the soft
 * reference will not be cleared.  Thus a sophisticated cache can, for example,
 * prevent its most recently used entries from being discarded by keeping
 * strong referents to those entries, leaving the remaining entries to be
 * discarded at the discretion of the garbage collector.
 *
 * @version  1.36, 02/26/09
 * @author   Mark Reinhold
 * @since    1.2
 */

public class SoftReference<T> extends Reference<T> {

    /** Timestamp clock, updated by the garbage collector
     */
    static private long clock;

    /** Timestamp updated by each invocation of the get method.  The VM may use
     * this field when selecting soft references to be cleared, but it is not
     * required to do so.
     */
    private long timestamp;

    /***
     * Creates a new soft reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new soft reference will refer to
     */
    public SoftReference(T referent) {
	super(referent);
	this.timestamp = clock;
    }

    /***
     * Creates a new soft reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new soft reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     *
     */
    public SoftReference(T referent, ReferenceQueue<? super T> q) {
	super(referent, q);
	this.timestamp = clock;
    }

    /***
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns <code>null</code>.
     *
     * @return   The object to which this reference refers, or
     *           <code>null</code> if this reference object has been cleared
     */
    public T get() {
	T o = super.get();
	if (o != null && this.timestamp != clock) 
            this.timestamp = clock;
	return o;
    }

}
<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开发中,SoftReference和WeakReference的使用有什么不同?4.使用WeakHashMap有什么注意事项?5.如何通过软引用实现一个简单的缓存?</think>### Java中WeakReferenceSoftReference的区别及使用场景 #### 核心区别 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、付费专栏及课程。

余额充值