【问题标题】:Why the private package String constructor (int, int, char[]) has been removed? [duplicate]为什么私有包 String 构造函数 (int, int, char[]) 被移除了? [复制]
【发布时间】: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


【解决方案1】:

是的,Stringchanged significantly in Java 7 update 6 - 现在独立的 String 对象永远不会共享底层 char[]。这绝对是一个权衡:

  • 字符串不再需要维护偏移量和长度(每个实例节省两个字段;不是很多,但它适用于每个字符串...)
  • 一个小字符串最终无法维持一个巨大的char[] 活着(根据您的帖子)
  • ...但以前成本低廉的操作现在最终会创建副本

在某些用例中,以前的代码会更好地工作 - 在其他用例中,新代码会更好地工作。不幸的是,听起来你在第一个营地。然而,我无法想象这个决定是轻率做出的 - 我怀疑针对不同的常见工作负载进行了很多测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-30
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    相关资源
    最近更新 更多