我应用是多线程与密集型字符串的处理。我们遇到过多的存储器消费量和分析已经证明,这是由于串数据。我认为,存储的消耗将大大受益于使用某些种类的轻量级模式实现,甚至超高速缓冲存储器(我知道肯定是串通常是重复的,虽然我没有任何硬数据,在这方面).

我已经看过Java恒的游泳池和串。实习生,但似乎它可以引起一些永久代的问题。

什么是最好的替代用于实施应用程序范围内,多线程的游泳池串在java?

编辑:还请参阅我的前,相关的问题: 怎么java实现摆模式串引擎盖下?

有帮助吗?

解决方案

注意:此答案使用现代运行时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 id = matcher.group(1);String id = new String(matcher.group(1));.

其他提示

这已经在JVM级别完成。您只需要确保您没有创建 new String每次都明确或隐式。

即不这样做:

String s1 = new String("foo");
String s2 = new String("foo");

这将在堆中创建两个实例。宁可这样做:

String s1 = "foo";
String s2 = "foo";

这将在堆中创建一个实例,两者都会引用相同(作为证据, s1 == s2 将返回 true 这里)。

也不使用 += 串联弦(循环):

String s = "";
for (/* some loop condition */) {
    s += "new";
}

+= 隐式创建一个 new String 每次都在堆中。宁愿这样做

StringBuilder sb = new StringBuilder();
for (/* some loop condition */) {
    sb.append("new");
}
String s = sb.toString();

如果可以的话,请使用 StringBuilder 或它的同步兄弟 StringBuffer 代替 String 用于“密集的弦处理”。它为这些目的提供了有用的方法,例如 append(), insert(), delete(), 等等。还请参阅 它的Javadoc.

有效地将字符串打包在内存中!我曾经写过一个超级内存有效的集合,其中字符串被存储为树。如果通过穿越字母来达到叶子,则该条目包含在集合中。也可以快速使用,并且非常适合存储大型词典。

而且不要忘记,几乎每个应用程序中的每个应用程序中,字符串通常是内存中最大的部分,因此,如果您需要它们,请不要关心它们。

插图:

您有3个琴弦:啤酒,豆类和血液。您可以创建这样的树结构:

B
+-e
  +-er
  +-ans
+-lood

对于街道名称列表,非常有效,这显然是固定词典最合理的,因为插入无法有效地完成。实际上,应该创建一次结构,然后序列化并刚刚加载。

Java 7/8

如果您正在做被接受的答案所说的内容,并且使用Java 7或更新的内容,则您不会做您所说的话。

实施 subString() 已经改变。

切勿编写依赖实现的代码,该实现可能会发生巨大变化,如果您依靠旧行为,可能会使情况变得更糟。

1950    public String substring(int beginIndex, int endIndex) {
1951        if (beginIndex < 0) {
1952            throw new StringIndexOutOfBoundsException(beginIndex);
1953        }
1954        if (endIndex > count) {
1955            throw new StringIndexOutOfBoundsException(endIndex);
1956        }
1957        if (beginIndex > endIndex) {
1958            throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
1959        }
1960        return ((beginIndex == 0) && (endIndex == count)) ? this :
1961            new String(offset + beginIndex, endIndex - beginIndex, value);
1962    }

因此,如果您使用Java 7或更新的答案,则需要收集的内存使用和垃圾的两倍。

第一,决定如何应用程序和开发人员会遭受如果你消除一些分析。一个更快程序不你没有好处如果你双倍的雇员更替率过程!我想根据你的问题我们可以假设你通过这个测试了。

第二,如果不能消除创造一个目的,那你的下一个目标应该是确保它不会生存下去的伊甸收集。和解析,查找可能解决这个问题。然而,一个高速缓冲存储器"实施适当的"(我不同意这一基本前提,但我不会烦你的助理咆哮)通常带来的线争议。你会被替换一种存储器中的压力另一种。

有一个变化的分析查找语,受到低排序的附带损害通常从全面缓存,这是一个简单的预先计算的查询表(也见"性记忆化").该模式通常你看看这是 类安全枚举 (TSE).与谢你分析,通过它的谢检索相关的所列举的类型,然后你把串走。

是的文本,你在处理自由的形式,或没有输入有遵循硬性规范吗?如果很多你的文本呈现下降到一个固定的可能值,那么谢可以帮助你在这里,并提供一个更大的掌握:加上下文/语意到你的信息的创作,而不是在使用点。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top