以下是从WeakHashMap javadoc中摘录的内容:
基于哈希表实现的Map,具有弱键。当一个key不再被普通使用时,WeakHashMap中的条目将自动被删除。更准确地说,给定key的映射的存在不会阻止垃圾回收器丢弃该key,即使它被做为最终化对象、最终化并被回收。当一个key被丢弃时,它的条目从map中有效地删除,因此,这个类的行为与其他Map实现有所不同。
我的理解是:是的... 当WeakHaskMap中的某个Key没有剩余的外部引用时,那么该Key可能被GC回收,使得相关的Value也无法访问,所以它也(假设没有直接对其进行外部引用)可以被GC回收。
我将测试这个理论。这只是我对文档的解释... 我没有任何关于WeakHashMap的经验... 但我立刻看到了它作为“内存安全”对象缓存的潜力。
谢谢。 Keith。
编辑:探索WeakHashMap... 具体测试我的理论,即外部引用到特定key会导致该key被保留... 这是纯属胡说八道 ;-)
我的测试工具:
package forums;
import java.util.Set;
import java.util.Map;
import java.util.WeakHashMap;
import krc.utilz.Random;
public class WeakCache<K,V> extends WeakHashMap<K,V>
{
private static final int NUM_ITEMS = 2000;
private static final Random RANDOM = new Random();
private static void runTest() {
Map<String, String> cache = new WeakCache<String, String>();
String key;
for (int i=0; i<NUM_ITEMS; ++i ) {
key = RANDOM.nextString();
cache.put(key, RANDOM.nextString());
}
System.out.println("There are " + cache.size() + " items of " + NUM_ITEMS + " in the cache before GC.");
Set<String> keys = cache.keySet();
System.out.println("There are " + keys.size() + " keys");
System.gc();
System.out.println("There are " + cache.size() + " items of " + NUM_ITEMS + " remaining after GC");
System.out.println("There are " + keys.size() + " keys");
}
public static void main(String[] args) {
try {
for (int i=0; i<20; ++i ) {
runTest();
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
一个测试运行的结果(我认为相当令人困惑):
There are 1912 items of 2000 in the cache before GC.
There are 1378 keys
There are 1378 items of 2000 remaining after GC
There are 909 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 1961 items of 2000 remaining after GC
There are 1588 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 1936 items of 2000 remaining after GC
There are 1471 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1669 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1264 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1770 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1679 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1774 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1668 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1834 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 429 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
看起来在我的代码执行过程中,密钥仍然会消失......可能需要在GC提示之后进行微睡眠,以便让GC有时间完成它的工作。不管怎样,这种“不稳定性”是有趣的行为。
编辑2:是的,在System.gc();
之后直接添加try{Thread.sleep(10);}catch(Exception e){}
可以使结果“更可预测”。
There are 1571 items of 2000 in the cache before GC.
There are 1359 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
.... and so on for 20 runs ...
嗯...当垃圾回收在真实应用程序中任意时间触发时,完全消失的缓存...没有多大用处...嗯...我想WeakHashMap是用来干什么的?;-)
最后编辑,我保证
这是我的krc/utilz/Random(在上面的测试中使用)
package krc.utilz;
import java.io.Serializable;
import java.nio.charset.Charset;
public class Random extends java.util.Random implements Serializable
{
private static final long serialVersionUID = 34324;
public static final int DEFAULT_MIN_STRING_LENGTH = 5;
public static final int DEFAULT_MAX_STRING_LENGTH = 25;
public Random() {
super();
}
public Random(long seed) {
super(seed);
}
public double nextDouble(double lo, double hi) {
double n = hi - lo;
double i = super.nextDouble() % n;
if (i < 0) i*=-1.0;
return lo + i;
}
public int nextInt(int lo, int hi)
throws IllegalArgumentException
{
if(lo >= hi) throw new IllegalArgumentException("lo must be < hi");
int n = hi - lo + 1;
int i = super.nextInt() % n;
if (i < 0) i = -i;
return lo + i;
}
public int nextInt(int lo, int hi, int xlo, int xhi)
throws IllegalArgumentException
{
if(xlo < lo) throw new IllegalArgumentException("xlo must be >= lo");
if(xhi > hi) throw new IllegalArgumentException("xhi must be =< hi");
if(xlo > xhi) throw new IllegalArgumentException("xlo must be >= xhi");
int i;
do {
i = nextInt(lo, hi);
} while(i>=xlo && i<=xhi);
return(i);
}
public String nextString()
throws IllegalArgumentException
{
return(nextString(DEFAULT_MIN_STRING_LENGTH, DEFAULT_MAX_STRING_LENGTH));
}
public String nextString(int minLen, int maxLen)
throws IllegalArgumentException
{
if(minLen < 0) throw new IllegalArgumentException("minLen must be >= 0");
if(minLen > maxLen) throw new IllegalArgumentException("minLen must be <= maxLen");
return(nextString(minLen, maxLen, 'A', 'z', '[', '`'));
}
public String nextString(int minLen, int maxLen, char lo, char hi)
throws IllegalArgumentException
{
if(lo < 0) throw new IllegalArgumentException("lo must be >= 0");
String retval = null;
try {
int n = minLen==maxLen ? maxLen : nextInt(minLen, maxLen);
byte b[] = new byte[n];
for (int i=0; i<n; i++)
b[i] = (byte)nextInt((int)lo, (int)hi);
retval = new String(b, Charset.defaultCharset().name());
} catch (Exception e) {
e.printStackTrace();
}
return retval;
}
public String nextString(int minLen, int maxLen, char lo, char hi, char xlo, char xhi)
throws IllegalArgumentException
{
if(lo < 0) throw new IllegalArgumentException("lo must be >= 0");
String retval = null;
try {
int n = minLen==maxLen ? maxLen : nextInt(minLen, maxLen);
byte b[] = new byte[n];
for (int i=0; i<n; i++) {
b[i] = (byte)nextInt((int)lo, (int)hi, (int)xlo, (int)xhi);
}
retval = new String(b, Charset.defaultCharset().name());
} catch (Exception e) {
e.printStackTrace();
}
return retval;
}
}