我有一个像这样的静态成员的类:
class C
{
static Map m=new HashMap();
{
... initialize the map with some values ...
}
}
AFAIK,这会在程序结束时消耗内存。我想知道,如果我能用软引用解决它,就像这样:
class C
{
static volatile SoftReference<Map> m=null;
static Map getM() {
Map ret;
if(m == null || (ret = m.get()) == null) {
ret=new HashMap();
... initialize the map ...
m=new SoftReference(ret);
}
return ret;
}
}
问题是
答案 0 :(得分:4)
首先,上面的代码不是线程安全的。
其次,虽然它在理论上有效,但我怀疑是否有一个现实的情况,它会得到回报。想一想:为了使它有用,地图的内容必须是:
在这里,1.和2.有点矛盾 - 大型物体也需要更长的时间来创作。
答案 1 :(得分:2)
如果您对getM
的访问权限是单线程的,并且它只充当缓存,那么这是可以的。
更好的选择是拥有固定大小的缓存,因为这可以提供一致的好处。
答案 2 :(得分:1)
getM()
应该是synchronized
,以避免m
被不同的线程同时初始化。
答案 3 :(得分:0)
这张地图有多大?用这种方式处理它是否值得?你有没有测量过它的内存消耗量(对于它的价值,我相信上面的内容一般都没问题,但我的第一个优化问题是“它真的能拯救我”)。
您将返回对地图的引用,因此您需要确保您的客户端不会保留此引用(并防止垃圾回收)。也许你的类可以保存引用,并提供一个getKey()方法来代表客户端访问地图的内容?这样你就可以在一个地方保持对地图参考的控制。
如果地图被垃圾收集并且两个线程同时点击getMap()
,我会同步上面的内容。否则你将同时创建两个地图!
答案 4 :(得分:0)
也许您正在寻找WeakHashMap?然后地图中的条目可以单独进行垃圾收集。
虽然根据我的经验它没有多大帮助,所以我改为使用LinkedHashMap构建一个LRU缓存。优点是我可以控制尺寸,使其不会太大而且仍然有用。
答案 5 :(得分:0)
我想知道,如果我能用软参考解决它
您想要解决的它是什么?您是否遇到内存问题,或者您是否过早地进行了优化?
无论如何,
如果您要使用它,应该稍微改变一下。如前所述,它不是线程安全的。多个线程可以同时访问该方法,允许创建集合的多个副本。如果这些集合随后被强烈引用到程序的其余部分,那么最终会消耗更多内存,而不是更少
使用SoftReferences的一个原因是为了避免内存不足,因为除了在VM抛出OutOfMemoryError
之前将 之前没有合同。因此,除了在首次使用之前不创建缓存,这种方法没有保证的好处。
答案 6 :(得分:0)
我注意到代码的第一件事是它将泛型与原始类型混合在一起。这只会导致一团糟。 JDK7中的javac有-Xlint:rawtypes
可以在故障开始之前快速发现这种错误。
代码不是线程安全的,但使用静态代码,因此在所有线程中发布。您可能不希望它为synchronized
,因为如果多线程计算机上存在争议则会导致问题。
对整个缓存使用SoftReference
的问题是,在清除引用时会导致峰值。在某些情况下,使用ThreadLocal<SoftReference<Map<K,V>>>
可以更好地解决峰值和帮助线程安全,但代价是不在线程之间共享。
但是,创建更智能的缓存更加困难。通常,您最终会得到引用键的值。有一些方法可以解决这个问题。我不认为ephemerons(基本上是一对链接的Reference
)将制作JDK7。您可能会发现值得关注的Google收藏集(虽然我没有)。
java.util.LinkedHashMap
提供了一种简单的方法来限制缓存条目的数量,但是如果您无法确定条目的大小,并且如果它停止收集大型对象系统可能会导致问题,则没有太大用处例如ClassLoader
s。有些人说你不应该把缓存驱逐放到垃圾收集器的一时兴起,但有些人说你不应该使用GC。