String.substring() 的性能与手动查找复制的 char[] 数组相比如何?

How does the performance of String.substring() compare with manual lookups into a copied char[] array?

我正在研究一个连续扫描大量相对较短的字符串并从中生成大量子字符串的函数。该函数将用于大容量字符串处理系统。我更喜欢先优化内存,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,两者都创建相同数量的新 strings/the substring() 内存泄漏已在不久前修复),并且 CPU 明智的是,由于对子字符串的不断查找,char[] 版本获胜。这听起来正确吗?我在分析中遗漏了什么吗?


解法注意事项 根据以下答案,functionB 似乎是最快的。还要注意 functionParent 中有一个 StringBuilder - StringBuilder 有一个 1append(char[], index, length)` 函数

String.substring - 除了绑定检查,通过调用 new String(value, beginIndex, subLen) 结束 - 除非结果是整个原始字符串,在这种情况下它只是 returns 原始字符串.

所以我会用你的第二个/“functionB”例子。

如果您对 String 操作合并大量 substringappend 类似操作有内存压力,您应该了解 CharSequence 抽象。许多 API 已经准备好使用这些代替 String.

由于 String 本身实现了 CharSequence,您可以更改您的方法以接受 CharSequence 输入而不是 String,而无需改变它们的用途。 StringsubSequence 实现与 substring 相同,因此复制内容,但您可以使用 CharBuffer.wrap(string, start, end).

创建子序列而不复制

如前所述,大多数操作都支持 CharSequence 输入,尤其是您的用例

请注意,StringBuilder 也实现了 CharSequence,因此允许您的操作往返,而无需创建中间 String 副本。