Mat*_*ias 63 java caching weak-references
Java的WeakHashMap经常被认为对缓存很有用.虽然它的弱引用是根据地图的键而不是它的值来定义的,但这似乎很奇怪.我的意思是,这是我想要缓存的值,除了缓存之外没有其他人强烈引用它们,我想要收集垃圾,不是吗?
以哪种方式有助于保持对密钥的弱引用?如果你这样做ExpensiveObject o = weakHashMap.get("some_key")
,那么我希望缓存保持为'o',直到调用者不再持有强引用,并且我根本不关心字符串对象"some_key".
我错过了什么吗?
Cow*_*wan 109
WeakHashMap 作为缓存并不实用,至少大多数人都会想到它.正如你所说,它使用弱键,而不是弱值,所以它不是为大多数人想要使用它而设计的(实际上,我看到人们使用它,不正确).
WeakHashMap主要用于保存关于其生命周期无法控制的对象的元数据.例如,如果您有一堆对象通过您的类,并且您希望跟踪有关它们的额外数据,而不需要在它们超出范围时得到通知,并且不引用它们使它们保持活动状态.
一个简单的例子(以及我之前使用的一个例子)可能是这样的:
WeakHashMap<Thread, SomeMetaData>
Run Code Online (Sandbox Code Playgroud)
您可以在哪里跟踪系统中的各种线程正在做什么; 当线程死亡时,该条目将从您的地图中静默删除,如果您是最后一次引用该线程,则不会使该线程被垃圾收集.然后,您可以遍历该映射中的条目,以找出有关系统中活动线程的元数据.
请参阅WeakHashMap而不是缓存!欲获得更多信息.
对于你所使用的缓存类型,要么使用专用缓存系统(例如EHCache),要么使用google-collections的 MapMaker类 ; 就像是
new MapMaker().weakValues().makeMap();
Run Code Online (Sandbox Code Playgroud)
会做你想做的事,或者如果你想得到想象,你可以添加定时到期:
new MapMaker().weakValues().expiration(5, TimeUnit.MINUTES).makeMap();
Run Code Online (Sandbox Code Playgroud)
uck*_*man 35
主要用途WeakHashMap
是当你的键映射消失时你想要消失的映射.缓存是相反的 - 当你的值消失时,你想要消失的映射.
对于缓存,你想要的是一个Map<K,SoftReference<V>>
.SoftReference
当内存变紧时,A 将被垃圾收集.(将其与a进行对比WeakReference
,只要不再对其指示对象进行硬引用,就可以将其清除.)您希望引用在缓存中是软的(至少在键值映射不会过时的情况下) ),从那时起,如果您以后查找它们,您的值仍有可能仍在缓存中.如果引用很弱,那么你的值将立即被gc'd,从而破坏了缓存的目的.
为方便起见,您可能希望隐藏实现中的SoftReference
值Map
,以便缓存看起来是类型<K,V>
而不是<K,SoftReference<V>>
.如果你想这样做,这个问题就网上可用的实现提出了建议.
另请注意,当您SoftReference
在a中使用值时Map
,必须执行某些操作以手动删除已清除的键值对SoftReferences
- 否则您的内容Map
将永远增大,并且内存泄漏.
另一件需要考虑的事情是,如果采用该Map<K, WeakReference<V>>
方法,该值可能会消失,但映射不会.根据使用情况,您最终可能会得到一个包含许多条目的地图,这些条目的弱引用已经过GC.
您需要两个映射:一个映射在缓存键和弱引用值之间,另一个映射在弱引用值和键之间的相反方向映射.而且你需要一个引用队列和一个清理线程.
当引用的对象不能再被访问时,弱引用能够将引用移动到队列中.该队列必须由清理线程排干. 对于清理,有必要获取参考密钥. 这就是为什么需要第二张地图的原因.
以下示例显示如何使用弱引用的哈希映射创建缓存.运行该程序时,您将获得以下输出:
$ javac -Xlint:unchecked Cache.java && java Cache {even: [2, 4, 6], odd: [1, 3, 5]} {even: [2, 4, 6]}
第一行显示在删除对奇数列表的引用之前的高速缓存的内容,并且在删除了赔率之后的第二行.
这是代码:
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Cache<K,V>
{
ReferenceQueue<V> queue = null;
Map<K,WeakReference<V>> values = null;
Map<WeakReference<V>,K> keys = null;
Thread cleanup = null;
Cache ()
{
queue = new ReferenceQueue<V>();
keys = Collections.synchronizedMap (new HashMap<WeakReference<V>,K>());
values = Collections.synchronizedMap (new HashMap<K,WeakReference<V>>());
cleanup = new Thread() {
public void run() {
try {
for (;;) {
@SuppressWarnings("unchecked")
WeakReference<V> ref = (WeakReference<V>)queue.remove();
K key = keys.get(ref);
keys.remove(ref);
values.remove(key);
}
}
catch (InterruptedException e) {}
}
};
cleanup.setDaemon (true);
cleanup.start();
}
void stop () {
cleanup.interrupt();
}
V get (K key) {
return values.get(key).get();
}
void put (K key, V value) {
WeakReference<V> ref = new WeakReference<V>(value, queue);
keys.put (ref, key);
values.put (key, ref);
}
public String toString() {
StringBuilder str = new StringBuilder();
str.append ("{");
boolean first = true;
for (Map.Entry<K,WeakReference<V>> entry : values.entrySet()) {
if (first)
first = false;
else
str.append (", ");
str.append (entry.getKey());
str.append (": ");
str.append (entry.getValue().get());
}
str.append ("}");
return str.toString();
}
static void gc (int loop, int delay) throws Exception
{
for (int n = loop; n > 0; n--) {
Thread.sleep(delay);
System.gc(); // <- obstinate donkey
}
}
public static void main (String[] args) throws Exception
{
// Create the cache
Cache<String,List> c = new Cache<String,List>();
// Create some values
List odd = Arrays.asList(new Object[]{1,3,5});
List even = Arrays.asList(new Object[]{2,4,6});
// Save them in the cache
c.put ("odd", odd);
c.put ("even", even);
// Display the cache contents
System.out.println (c);
// Erase one value;
odd = null;
// Force garbage collection
gc (10, 10);
// Display the cache again
System.out.println (c);
// Stop cleanup thread
c.stop();
}
}
Run Code Online (Sandbox Code Playgroud)