【发布时间】:2015-06-09 18:06:06
【问题描述】:
在 Java 6 中,有一个包私有构造函数来返回一个新的字符串,其中偏移量发生了变化。
643 // Package private constructor which shares value array for speed.
644 String(int offset, int count, char value[]) {
645 this.value = value;
646 this.offset = offset;
647 this.count = count;
648 }
它在 Java 7 中被标记为已弃用,并在 Java 8 中被删除。我依赖于一些 API 反复调用 subSequence,直到遇到性能问题。
深入研究代码,我看到subSequence 在 Java 6 中使用了这个构造函数。但就目前而言,它使用另一个复制底层数组并从所需和结束的偏移量开始的构造函数,因此使其成为 O( 1) 运算到 O(n)。
将有问题的调用替换为 subSequence 已将性能提高了 10 倍。
我想知道为什么会做出这样的改变。我唯一想到的是它可能会造成潜在的内存泄漏,例如:
String veryLargeString = ....;
String target = veryLargeString.substring(0, 10);
//assume I don't need anymore veryLargeString at this point
此时底层的 char 数组不能被 GC,因为它仍然被目标 String 使用。因此,您在内存中有一个大数组,但您只需要它的前 10 个值。
这是唯一一个好的用例,还是有其他原因导致这个构造函数被移除?
【问题讨论】:
-
我认为部分想法可能是,在极少数情况下,这确实会导致问题,您可以通过使用自己的类包装
char[]来解决它。不理想,但它比追踪模糊的内存泄漏更直接。 -
@biziclop:最简单的 O(1) 实现是
CharBuffer.wrap(string).subSequence(start, end),它在 O(1) 中为您生成CharSequence,而无需滚动您自己的任何东西。 -
我相信,主要动机是
String和它的char[]的最终“共同定位”。现在它们定位在远处,这是对缓存行的主要惩罚。如果每个String都拥有自己的char[],JVM可以将它们合并在一起,读取速度会快很多。
标签: java string memory-leaks