1. 适用场景
- 弱引用:适用于当对象不是必须存活,在下次垃圾回收时,只要对象没有强引用指向它,就会被回收。比如在缓存场景中,如果缓存中的数据即使丢失,也不会对系统造成严重影响,就可以使用弱引用。例如,在一个图片缓存系统中,当内存紧张时,缓存的图片可以被回收。
- 软引用:适用于当内存足够时,对象可以一直存在,但当内存不足时,会被回收。常用于实现缓存,当内存充足时,缓存的数据能一直保留以提高系统性能,而当内存紧张时,缓存数据可以被释放以避免内存溢出。例如,数据库查询结果的缓存,如果内存够用就一直缓存,内存不够就释放。
2. 在自定义集合类中使用方式
- 使用弱引用:在自定义集合类中,可以将需要弱引用管理的对象包装成
WeakReference
对象再放入集合。例如:
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class WeakReferenceCollection {
private List<WeakReference<Object>> list = new ArrayList<>();
public void addObject(Object obj) {
list.add(new WeakReference<>(obj));
}
public Object getObject(int index) {
WeakReference<Object> weakReference = list.get(index);
return weakReference.get();
}
}
- 使用软引用:类似地,使用
SoftReference
包装对象放入集合。
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
public class SoftReferenceCollection {
private List<SoftReference<Object>> list = new ArrayList<>();
public void addObject(Object obj) {
list.add(new SoftReference<>(obj));
}
public Object getObject(int index) {
SoftReference<Object> softReference = list.get(index);
return softReference.get();
}
}
3. 可能带来的问题
- 弱引用:
- 对象可能已被回收:在获取弱引用对象时,它可能已经被垃圾回收了,导致获取到
null
,这可能使程序出现空指针异常。
- 性能开销:每次获取对象时需要检查是否为
null
,并且垃圾回收器需要额外处理弱引用,可能带来一定性能开销。
- 软引用:
- 回收时机不可控:虽然知道内存不足时软引用对象会被回收,但具体何时回收并不确定,这可能导致在使用对象时才发现对象已被回收,影响程序逻辑。
- 内存压力评估困难:很难准确评估软引用对象占用内存对系统整体内存压力的影响,可能导致过度使用软引用缓存,在内存紧张时才发现释放软引用对象也无法满足内存需求。
4. 解决问题的方法
- 针对弱引用:
- 空指针检查:在获取弱引用对象后,始终进行空指针检查,避免空指针异常。如上述
WeakReferenceCollection
类的getObject
方法获取对象后进行空指针判断。
- 优化性能:合理设计缓存更新策略,减少对弱引用对象的频繁获取和检查。例如,可以在缓存命中率较高时,定期清理已失效的弱引用对象,而不是每次获取都检查。
- 针对软引用:
- 兜底策略:为可能被回收的软引用对象设计兜底方案,例如当软引用对象被回收后,可以重新从数据源获取数据。
- 内存监控:结合系统的内存监控机制,合理调整软引用缓存的大小。比如,当内存使用率达到一定阈值时,主动清理部分软引用对象,避免内存过度紧张。