java里的弱引用
真是惭愧啊,搞了好几年Java,居然才知道Java里的弱引用!
"Java拥有垃圾回收机制,我们不需要手工释放对象",在讲到java的垃圾回收时,老师们总是这样一句带过。似乎Java真的很智能(实际上确实很智能),但是有时候她的垃圾回收机制并不能很好的理解我们的意图,考虑这么一种情况:
有一个Swing面板JPanel中有一个成员变量obj,窗体加载这个JPanel的时候,将obj加入一个全局map(static类的static属性)中,如果JPanel被卸载了,obj会被回收吗?
?
我们肯定希望obj会被回收,因为JPanel已经被卸载了,作为成员变量的obj也就没有存在的意义了。
?
但是,实际上,这个obj不会被回收,因为它还被那个全局的map引用!这还不是最糟糕的,万一这个obj还引用其它对象,这些对象也一律不会被回收,这就造成了很大的内存浪费。幸运的是,java提供了WeakReference解决这个问题。看下面的代码:
public class Test { public static Map map=new HashMap(); public static void main(String[] args){ MyObject obj=new MyObject("obj1"); map.put("obj1",obj); test(); } static void test(){ Thread t=new Thread(new Runnable() { @Override public void run() { int i=0; while (true){ System.out.println(i++); System.gc(); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } } }); t.start(); }}class MyObject{ String id; public MyObject(String id){ this.id=id; } @Override public void finalize() { System.out.println(id + " is finalized"); }}将MyObject类的一个实例(obj)放入一个全局map,程序跳入test方法后,每隔1s调用垃圾回收器,虽然此时已经超出了obj的作用域,但是因为map还引用着obj,所以它不会被回收。
修改一下代码,将map.put("obj1",obj)改为map.put("obj1",new WeakReference(obj)),再运行程序,可以发现控制台很快输出"obj1 is finalized",说明对象被回收了。
有人可能疑惑,存入map的是WeakReference,要用obj怎么办?WeakReference提供了一个get方法,可以返回包装的对象,如果返回null,说明对象已经被回收了。
Java还提供了SoftReference(软引用),当内存紧张时,它所包装的对象可能被回收,API里说用它来做缓存不错,大家可以自行研究。