Java之道系列:WeakHashMap实现浅析

举个栗子

关于Reference对象,java.lang.ref包的文档说了一堆,跑起来看看才是王道,

{() throws Throwable {System.out.println(“finalize#” + this);super.finalize();}} private static ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>();static {new Thread(new Runnable() {() {while (true) {Reference ref = null;try {ref = queue.remove();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(“removed#” + ref);}}}).start();}(String[] args) throws Exception{PhantomReference<Foo> pr = pr(); // phantom reachableWeakReference<Foo> wr = wr(); // weakly reachableSoftReference<Foo> sr = sr(); // softly reachableSystem.gc();Thread.sleep(2000);System.out.println(“pr.isEnqueued()#”+pr.isEnqueued());System.out.println(“wr.get()#”+wr.get());System.out.println(“sr.get()#”+sr.get());}private static PhantomReference<Foo> pr() {Foo foo = new Foo();PhantomReference<Foo> pr = new PhantomReference<Foo>(foo, queue);return pr;}private static WeakReference<Foo> wr() {Foo foo = new Foo();WeakReference<Foo> wr = new WeakReference<Foo>(foo, queue);return wr;}private static SoftReference<Foo> sr() {Foo foo = new Foo();SoftReference<Foo> sr = new SoftReference<Foo>(foo, queue);return sr;}

输出是这样的,

removed#java.lang.ref.WeakReference@d48785finalize#me.kisimple.just4fun.Foo@10d3d99finalize#me.kisimple.just4fun.Foo@fdd15bpr.isEnqueued()#falsewr.get()#nullsr.get()#me.kisimple.just4fun.Foo@a0fbd6

有时候是这样的,

finalize#me.kisimple.just4fun.Foo@ae8542finalize#me.kisimple.just4fun.Foo@161c602removed#java.lang.ref.WeakReference@1f4ea9dpr.isEnqueued()#falsewr.get()#nullsr.get()#me.kisimple.just4fun.Foo@128f03

finalize#跟removed#的顺序并不固定。 下面我们就根据这个输出来分析下当

the reachability of the referent has changed to the value corresponding to the type of the reference

时,也就是注释中的xxx reachable,referent的回收和reference入队列这两个操作。

finalizeenqueue

但是API文档中说道,

Some time after the garbage collector determines that the reachability of the referent has changed to the value corresponding to the type of the reference, it will add the reference to the associated queue.

但从上面的栗子只看到WeakReference的行为符合文档的说明,是有bug还是栗子有问题?

内存泄漏

关于WeakHashMap,,API文档说明如下,

More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.

也就是说,即使WeakHashMap持有了key对象也不会阻止这个key对象被回收,也就相当于说,WeakHashMap只是持有了该key对象的一个WeakReference而已。当key对象被回收之后,相应的mapping也会被回收。来看下面的栗子,

{() throws Throwable {System.out.println(“finalize#” + this);super.finalize();}}{private long id;public Bar(long id) {this.id = id;}(Object obj) {return obj instanceof Bar ?((Bar)obj).id == this.id : false;}() {return (int) (id ^ (id >>> 32));}}private static Map<Bar, Object> sm = new HashMap<Bar, Object>();private static Map<Bar, Object> wm = new WeakHashMap<Bar, Object>();(String[] args) throws Exception{strongMap();weakMap();System.gc();Thread.sleep(2000);System.out.println(sm.get(new Bar(27)));System.out.println(wm.get(new Bar(127)));}() {Foo foo = new Foo();sm.put(new Bar(27), foo);}() {Foo foo = new Foo();wm.put(new Bar(127), foo);}

输出如下,WeakHashMap持有的mapping妥妥的被回收了,而普通的HashMap则不会。

me.kisimple.just4fun.Main$Foo@2dce0null

依靠这个特性WeakHashMap可以代替HashMap来防止一些内存泄漏,具体可参考这篇文档。

WeakHashMap每一个成功者都有一个开始。勇于开始,才能找到成功的路。

Java之道系列:WeakHashMap实现浅析

相关文章:

你感兴趣的文章:

标签云: