软引用(Soft Reference)
表示一个对象处在有用但非必须的状态。如果一个对象只具有软引用,在内存空间充足时,GC就不会回收该对象;当内存空间不足时,GC会回收该对象的内存(回收发生在OutOfMemoryError之前)。
public static void main(String[] args) {
SoftReference<Cache > sr = new SoftReference<Cache >(new Cache ());
System.out.println(sr.get());
}
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被GC回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中,以便在恰当的时候将该软引用回收。但是由于GC线程的优先级较低,通常手动调用System.gc()并不能立即执行GC,因此弱引用所引用的对象并不一定会被马上回收。
弱引用(Weak Reference)
用来描述非必须的对象。它类似软引用,但是强度比软引用更弱一些:弱引用具有更短的生命.GC在扫描的过程中,一旦发现只具有被弱引用关联的对象,都会回收掉被弱引用关联的对象。换言之,无论当前内存是否紧缺,GC都将回收被弱引用关联的对象。
WeakReference<Cache > wr = new WeakReference<Cache >(new Cache ());
同样弱引用也可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被GC回收了,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中,以便在恰当的时候将该弱引用回收。
ReferenceQueue
/**
* Reference queues, to which registered reference objects are appended by the
* garbage collector after the appropriate reachability changes are detected.
*/
- 引用队列,在检测到适当的可到达性更改后,垃圾回收器将已注册的引用对象添加到该队列中。但实际内部并非有实际的存储结构,它的存储是依赖于内部节点之间的关系来表达。可以理解为queue是一个类似于链表的结构,这里的节点其实就是reference本身。可以理解为queue为一个链表的容器,其自己仅存储当前的head节点,而后面的节点由每个reference节点自己通过next来保持即可。
- queue的意义在于,我们可以在外部对这个queue进行监控。即如果有对象即将被回收,那么相应的reference对象就会被放到这个queue里。我们拿到reference,就可以再作一些事务。
而如果不使用的话,就只有不断地轮询reference对象,通过判断里面的get是否返回null( phantomReference对象不能这样作,其get始终返回null,因此它只有带queue的构造函数 )。这两种方法均有相应的使用场景,取决于实际的应用。如weakHashMap中就选择去查询queue的数据,来判定是否有对象将被回收。而ThreadLocalMap,则采用判断get()是否为null来作处理。 -
如果我们在创建一个引用对象时,指定了ReferenceQueue,那么当引用对象指向的对象达到合适的状态(根据引用类型不同而不同)时,GC 会把引用对象本身添加到这个队列中,方便我们处理它,因为“引用对象指向的对象 GC 会自动清理,但是引用对象本身也是对象(是对象就占用一定资源),所以需要我们自己清理。”
ReferenceQueue< Cache > rq=new ReferenceQueue();
WakeReference <Cache>wr=new WakeReference(new Cache (),rq);
需要注意的是如果是显示声明的对象,如下图所示,如果不置为null,那么永远存在一个指向该对象的强引用,如下图,将不会对该对象进行回收
Cache cache = new Cache();
ReferenceQueue<Cache> referenceQueue = new ReferenceQueue();
WeakReference wr = new WeakReference(cache, referenceQueue);
//cache = null;
System.gc();
所以显示声明一个需要软引用或者弱引用的对象时,要设置为null,取消对他的强引用,才会在GC时回收
ReferenceQueue< Cache > rq=new ReferenceQueue();
Cache cache = new Cache ();
WakeReference wr=new WakeReference(cache ,rq);
cache = null;
System.gc();
应用场景
两者都可以实现缓存功能,但软引用实现的缓存通常用在服务端,而在移动设备中的内存更为紧缺,对垃圾回收更为敏感,因此android中的缓存通常是用弱引用来实现(比如LruCache)