在单机版系统中需要实现一个简单的缓存功能(不使用分布式缓存系统),在内存中用一个map来实现就行了,通常的map可用 LinkedHashMap也可以用WeakHashMap 来实现,他们的区别在于淘汰机制上,前者是在构建时设置一个阀值(或者是可以在回收的时候决定那个对象优先被回收),当到了一个阀值之后就会决定老的对象是否要被淘汰。而后者WeakHashMap 是基于虚拟机的垃圾回机制来淘汰的,回收时,容器中哪个对象对回收完全是由GC来决定的。
这里通过一些代码来来说明WeakHashMap的特性,首先第一个代码,可以顺利执行完成:
public void test1() throws Exception { //List<byte[][]> keys = new ArrayList<byte[][]>(); byte[][] key = null; WeakHashMap<byte[][], byte[][]> maps = new WeakHashMap<byte[][], byte[][]>(); for (int i = 0; i < 10000; i++) { key = new byte[1000][1000]; maps.put(key, new byte[1000][1000]); // System.gc(); System.err.println(i); System.err.println(" size" + maps.size()); } }
从输出结果上可以发现,size的大小,会由小变大,突然变小,然后再由小变大。这个说明垃圾回收期在器作用,这个和jdk的说明文档是一致的:
/ * An entry in a <tt>WeakHashMap</tt> will automatically be removed when * its key is no longer in ordinary use. 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 <tt>Map</tt> * implementations. */
当GC开始回收的时候会发现,map的key已经不被使用了,即使map中key和value的映射已然存在,也不能阻止map的key被GC回收掉。当map的key被回收了之后,value对象也会被顺利地回收的。
再看下面这个代码:
public void test2() throws Exception { List<byte[][]> keys = new ArrayList<byte[][]>(); byte[][] key = null; WeakHashMap<byte[][], byte[][]> maps = new WeakHashMap<byte[][], byte[][]>(); for (int i = 0; i < 10000; i++) { key = new byte[1000][1000]; keys.add(key); maps.put(key, new byte[1000][1000]); // System.gc(); System.err.println(i); System.err.println(" size" + maps.size()); } }
test2()执行到一半就会抛出OOM异常,这份代码和上一份代码的唯一区别就是,map的key放到一个list中,这样能保证方法体中的所有key都是被引用的,所以在启动垃圾回收的时候,weak中的key一个都不会被自动回收,所以OOM就在所难免了。
所以在使用WeakHashMap的时候,千万注意,使用完某个key如果希望对象会被自动回收,需要与map的key的所有引用关系切断。