优化Java中一系列字符串的内存使用

Kis*_*nan 9 java string memory-management

我有大量的名称 - 值对(大约100k),我需要存储在某种缓存(比如一个哈希映射)中,其中值是一个平均大小约为30k字节的字符串.

现在我知道一个事实,即大量的值具有完全相同的字符串数据.为了避免必须多次分配相同的字符串数据,我想以某种方式重用先前分配的字符串,从而消耗更少的内存.此外,这需要相当快.即,逐个扫描所有先前分配的值不是一种选择.

关于如何解决这个问题的任何建议?

jam*_*mes 10

千万不能使用中的String.intern(已经有过多年的与此相关的各种内存问题).相反,创建自己的缓存,类似于String.intern.基本上,你想要一个Map,每个键映射到自己.然后,在缓存任何字符串之前,你"实习"它:

private Map<String,WeakReference<String>> myInternMap = new WeakHashMap<String,,WeakReference<String>>();
public String intern(String value) {
  synchronized(myInternMap) {
    WeakReference<String> curRef = myInternMap.get(value);
    String curValue = ((curRef != null) ? curRef.get() : null);
    if(curValue != null) {
      return curValue;
    }

    myInternMap.put(value, new WeakReference<String>(value));
    return value;
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您对键和值使用弱引用,以便不保留对不再使用的字符串的引用.

  • 不,这是非常糟糕的建议.对于现在过时的JVM,大多数此类注释都涉及相当古老的问题.对于长期共享的字符串,String.intern()绝对没有错.比自己更换卷轴的问题要少得多. (2认同)

Bri*_*new 9

String.intern()将在这里帮助你(最有可能).它会将同一字符串的多个实例解析为一个副本.

编辑:我建议这"最有可能"帮助.在什么情况下不会?实习字符串将具有永久存储这些内部字符串表示的效果.如果问题域是一次性过程,这可能不是问题.如果这是一个长时间运行的过程(例如Web应用程序),那么您可能会遇到问题.

我会毫不犹豫地说从来没有使用实习(我会犹豫,马上说从来没有做任何事情).然而,有些情况并不理想.