我正在研究一个连续扫描大量相对较短的字符串的函数,并从中生成大量的子字符串。该功能将用于高容量字符串处理系统。我更喜欢首先优化内存,CPU优先,因为我遇到的内存多于系统上的CPU压力。在这种情况下,性能如何比较:
//Java-ish PseudoCode
functionParent(List<String> strings) {
StringBuilder result;
for(String s : strings) {
result.appendAll(functionA(s));
}
}
functionA(String arg1) {
results.add(arg1.substring(i, i + length)); //hotspot here
}
和
//Java-ish PseudoCode
functionParent(List<String> strings) {
StringBuilder result;
for(String s : strings) {
result.appendAll(functionB(s.toCharArray()));
}
}
functionB(char[] arg1) {
results.add(new String(arg1,i, length)); //hotspot here
}
到目前为止,从我的测试中可以看出,内存方面它是一个清洗(char []分配可忽略不计并且不影响GC,两者都创建相同数量的新字符串/ substring()内存-leak在前一段时间被修复了),并且由于对子串的不断查找,因此CPU []版本获胜。这听起来不对吗?我在分析中遗漏了什么吗?
有关解决方案的说明
根据下面的答案,functionB
似乎是最快的。还要注意在functionParent中有一个StringBuilder - 而StringBuilder有一个1append(char [],index,length)`function
答案 0 :(得分:2)
List.map
- 除了绑定检查之外,还可以通过调用String.substring
来完成 - 除非结果是整个原始字符串,在这种情况下它只返回原始字符串。
所以我会使用你的第二个/“new String(value, beginIndex, subLen)
”例子。
答案 1 :(得分:1)
如果您在String
次操作中遇到大量substring
和append
类似操作的内存压力,您应该了解CharSequence
抽象。许多API已经准备好使用这些API代替String
。
由于String
本身实现了CharSequence
,您可以将方法更改为接受CharSequence
输入而不是String
而不更改其有用性。 subSequence
的{{1}}实现与String
的执行方式相同,因此会复制内容,但您可以创建子序列而不使用CharBuffer.wrap(string, start, end)
进行复制。
如上所述,大多数操作支持substring
输入,最明显的是用于您的用例
StringBuilder.append(CharSequence s)
StringBuilder.append(CharSequence s, int start, int end)
已提到的CharBuffer.wrap(CharSequence csq, int start, int end)
还有CharSequence.subSequence(int start, int end)
,但如上所述,如果基础序列为CharSequence
,则会获得副本,而String
则保证非复制行为
CharBuffer.wrap(char[] array, int offset, int length)
作为获取CharBuffer.wrap
数组的CharSequence
表示而无需复制的规范方法String.contentEquals(CharSequence)
Pattern.matcher(CharSequence)
请注意,char[]
也会实现StringBuilder
,因此可以在不需要创建中间CharSequence
副本的情况下实现操作的往返。