最好的选择串轻量级的执行Java
-
04-10-2019 - |
题
我应用是多线程与密集型字符串的处理。我们遇到过多的存储器消费量和分析已经证明,这是由于串数据。我认为,存储的消耗将大大受益于使用某些种类的轻量级模式实现,甚至超高速缓冲存储器(我知道肯定是串通常是重复的,虽然我没有任何硬数据,在这方面).
我已经看过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).与谢你分析,通过它的谢检索相关的所列举的类型,然后你把串走。
是的文本,你在处理自由的形式,或没有输入有遵循硬性规范吗?如果很多你的文本呈现下降到一个固定的可能值,那么谢可以帮助你在这里,并提供一个更大的掌握:加上下文/语意到你的信息的创作,而不是在使用点。