java - Java 中 String flyweight 实现的最佳替代方案

标签 java string memory-management pool flyweight-pattern

我的应用程序是多线程的,具有密集的字符串处理。我们正在经历过多的内存消耗,分析表明这是由于 String 数据造成的。我认为内存消耗会从使用某种享元模式实现甚至缓存中受益匪浅(我确信字符串经常重复,尽管我没有这方面的任何硬数据)。

我看过 Java 常量池和 String.intern,但它似乎会引发一些 PermGen 问题。

在 Java 中实现应用程序范围内的多线程字符串池的最佳替代方案是什么?

编辑:另见我之前的相关问题:How does java implement flyweight pattern for string under the hood?

最佳答案

注意:此答案使用的示例可能与现代运行时 JVM 库无关。特别是,substring 示例在 OpenJDK/Oracle 7+ 中不再是问题。

我知道这与人们经常告诉您的相反,但有时显式创建新的 String 实例可能是减少内存的重要方法。

因为字符串是不可变的,所以有几种方法利用了这一事实并共享支持字符数组以节省内存。但是,有时这实际上可以通过防止对这些数组的未使用部分进行垃圾回收来增加内存。

例如,假设您正在解析日志文件的消息 ID 以提取警告 ID。您的代码看起来像这样:

//Format:
//ID: [WARNING|ERROR|DEBUG] Message...
String testLine = "5AB729: WARNING Some really really really long message";

Matcher matcher = Pattern.compile("([A-Z0-9]*): WARNING.*").matcher(testLine);
if ( matcher.matches() ) {
    String id = matcher.group(1);
        //...do something with id...
}

但是看看实际存储的数据:

    //...
    String id = matcher.group(1);
    Field valueField = String.class.getDeclaredField("value");
    valueField.setAccessible(true);

    char[] data = ((char[])valueField.get(id));
    System.out.println("Actual data stored for string \"" + id + "\": " + Arrays.toString(data) );

这是整个测试行,因为匹配器只是将一个新的 String 实例包装在相同的字符数据周围。比较将 String id = matcher.group(1); 替换为 String id = new String(matcher.group(1)); 时的结果。

关于java - Java 中 String flyweight 实现的最佳替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2915511/

相关文章:

Java equals() 排序

java - Camunda 中中间抛出事件的模拟 Java 实现

java - Jar文件创建

javascript - JavaScript 有文字字符串吗?

string - 字符串标记化程序过滤器,例如Elasticsearch中的Shingle

objective-c - 在 UIViewController 中加载和卸载数据

java - 如何将 arraylist 的第一项移动到最后一个位置?

c - 为什么我存在未声明的变量?

汇编内存分配

python - 如何从 Python 中的字符串列表创建所有可能的长度为 100 个字符的句子