在Java中使用静态数据软引用防止内存不足
我有一个静态成员的类,如下所示:在Java中使用静态数据软引用防止内存不足,java,memory-management,memory-leaks,static,Java,Memory Management,Memory Leaks,Static,我有一个静态成员的类,如下所示: class C { static Map m=new HashMap(); { ... initialize the map with some values ... } } class C { static volatile SoftReference<Map> m=null; static Map getM() { Map ret; if(m == null || (ret = m.get()) ==
class C
{
static Map m=new HashMap();
{
... initialize the map with some values ...
}
}
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;
}
}
顺便说一句,这实际上会消耗内存直到程序结束。我在想,我是否可以用软引用来解决它,比如:
class C
{
static Map m=new HashMap();
{
... initialize the map with some values ...
}
}
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;
}
}
C类
{
静态易失性软参考m=null;
静态映射getM(){
地图检索;
如果(m==null | |(ret=m.get())==null){
ret=新的HashMap();
…初始化映射。。。
m=新的软参考(ret);
}
返回ret;
}
}
问题是
这张地图有多大?这样处理是否值得?你有没有测量过它的内存消耗量(就它的价值而言,我相信上面的内容一般都是可以的,但我关于优化的第一个问题是“它真正为我节省了什么”) 您将返回对映射的引用,因此需要确保您的客户端不会保留此引用(并防止垃圾收集)。也许您的类可以保存引用,并提供一个getKey()方法来代表客户端访问映射的内容?这样,您将在一个位置保持对地图引用的控制
我将同步上述内容,以防map被垃圾收集,两个线程同时命中
getMap()
。否则,您将同时创建两个贴图 如果您对getM
的访问是单线程的,并且它只充当缓存,那么这是可以的。
更好的替代方法是使用固定大小的缓存,因为这提供了一致的好处。首先,上面的代码不是线程安全的 第二,虽然它在理论上是可行的,但我怀疑是否有一个现实的场景能让它获得回报。想一想:为了让它有用,地图的内容必须是:
getM()
应该是同步的,以避免m
同时被不同的线程初始化。也许你正在寻找?然后可以分别对映射中的条目进行垃圾收集
尽管根据我的经验,这并没有多大帮助,所以我使用构建了一个LRU缓存。优点是我可以控制大小,这样它就不会太大,而且仍然有用
我在想,我是否可以用软引用来解决它
你想解决的问题是什么?您是遇到了内存问题,还是过早地进行了优化
无论如何
OutOfMemoryError
之前清除它们之外,没有其他约定。因此,除了在首次使用缓存之前不创建缓存之外,这种方法没有任何保证的好处关于代码,我注意到的第一件事是它混合了泛型和原始类型。那只会导致一片混乱。JDK7中的javac具有
-Xlint:rawtypes
功能,可以在出现问题之前快速发现此类错误
代码不是线程安全的,但使用静态,因此跨所有线程发布。您可能不希望它是同步的,因为在多线程机器上争用会导致问题
对整个缓存使用SoftReference
的一个问题是,清除引用时会导致峰值。在某些情况下,最好使用ThreadLocal
,这样可以分散尖峰并有助于线程安全,但代价是不在线程之间共享
但是,创建更智能的缓存更为困难。通常,最终的结果是值引用键。有很多方法可以解决这一点,这是一片混乱。我不认为蜉蝣(本质上是一对链接的Reference
s)会成为JDK7。你可能会发现谷歌收藏值得一看(尽管我没有)
java.util.LinkedHashMap
提供了一种简单的方法来限制缓存条目的数量,但是如果您不能确定条目有多大,它就没有多大用处,如果它停止收集大型对象系统,例如ClassLoader
s,则可能会导致问题。有人说你不应该让缓存逐出由垃圾收集器随意决定,但也有人说你不应该使用GC。WeakHashMap的问题在于,它是弱引用的键,而不是值。这对于针对HttpSession
保存数据之类的事情很有用,但对于缓存则不太有用。还请注意,当没有强引用时,JVM将立即收集弱引用对象,而当内存不足时,JVM将只收集SoftReference
。攻击性垃圾收集解释了它为什么不工作。不幸的是,似乎没有一个标准的SoftHashMap。WeakReference
s对于缓存来说是非常危险的。根据我的经验,NetBeans在使用了一段时间后,只需坐在那里,CPU 100%执行文件访问