软引用可以和一个引用队列联合使用,如果软引用所引用的对象被垃圾回收器回收,JVM就会把这个软引用加入到与之关联的引用队列中;
首先,我们看一个雇员信息查询系统的实例。我们将使用一个Java语言实现的雇员信息查询系统查询存储在磁盘文件或者数据库中的雇员人事档案信息。作为一个用户,我们完全有可能需要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息(同样,我们在浏览WEB页面的时候也经常会使用“后退”按钮)。这时我们通常会有两种程序实现方式:一种是把过去查看过的雇员信息保存在内存中,每一个存储了雇员档案信息的Java对象的生命周期贯穿整个应用程序始终;另一种是当用户开始查看其他雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的Java对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该雇员的档案信息的时候,重新构建该雇员的信息。很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。我们知道,访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度。
SoftReference的特点是她的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾回收线程对该java对象的回收; 一旦SoftReference保存了对一个java对象的软引用后,在垃圾回收线程对这个对象回收前,可以使用SoftReference类的get()方法返回java对象的强引用。一旦该对象回收之后,get方法返回null;
User u=new User(); SoftReference ref=new SoftReference(u);此时,对于User对象来说,有两个引用路径:来自u的强引用和ref的软引用,因此这个User对象是强可及对象;
u=null;结束对User实例的强引用,此时该对象成为了软可及对象。JVM的垃圾回收线程对软可及对象和其他一般对象进行了区别对待:软可及对象的清理是由垃圾收集线程根据特定算法按照内存需求决定的;在回收这些对象之前,可以通过 User user=(User)ref.get(); 重新获得对该实例的强引用,回收之后调用get只能得到null;
使用ReferenceQueue清除失去了软引用对象的SoftReference;
当软可及对象被回收之后,虽然这个SoftReference对象的get返回null,但是这个SoftReference对象已经不再具备存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。
ReferenceQueue queue=new ReferenceQueue(); SoftReference ref=new SoftReference(u,queue);如果在创建SoftReference对象时,使用了一个ReferenceQueue作为参数提供给SoftReference的构造方法,那么当SoftReference软引用的u被垃圾回收器回收的同时,ref所强引用的SoftReference对象被放入ReferenceQueue。
ReferenceQueue保存的对象是已经失去了软引用对象的Reference对象。 可以调用ReferenceQueue的poll检查是否有他所关心的非强可及对象被回收;如果队列为空返回null,否则返回队列中的最前面的一个Reference对象。
可以用来检查哪个SoftReference所软引用的对象已经被回收,之后可以将失去软引用对象的SoftReference清除掉。