【问题标题】:Is there a reason StringBuilder insert uses String.valueOf?StringBuilder插入使用String.valueOf是否有原因?
【发布时间】:2018-04-06 13:01:30
【问题描述】:

AbstractStringBuilder 的JDK 源代码中,append(int) 方法的实现方式不会分配不必要的内存(使用Integer.getChars 直接写入内部char[])。

insert 的实现使用String.valueOf,它返回一个新字符串,然后将该数据复制到数组中。创建垃圾字符串。

StringBuilder 不是减轻连接字符串的垃圾影响的要点之一。 insert 的无垃圾实现似乎微不足道。那为什么不呢?

Oracle JDK 和 OpenJDK 似乎都是这种情况。甚至在javadoc中提到:

整体效果就好像第二个参数被String.valueOf(int)方法转换成字符串,然后那个字符串的字符被插入到这个字符序列中指定的偏移量。

【问题讨论】:

  • insert 的实现不会影响“减轻连接字符串的垃圾影响”的目标,因为连接永远不需要 insert 操作。由于不太常见,减少代码重复被认为比减少垃圾更重要。显然。

标签: java garbage-collection stringbuilder


【解决方案1】:

如果您将insert(int,int) 与其他insert 方法进行比较,您会发现实现方法是保持简单,通过让单个insert(String) 方法完成所有实际工作来减少代码重复。

这是软件开发中的一种合理方法,首先创建一个简单的通用实现来处理所有情况,然后对实际应用程序和场景进行分析,以找到创建一个专门的、也许不是那么简单的优化版本的地方益处。似乎没有搜索到可以使用相同优化实现的其他地方。考虑到前面的测量显然没有将insert(int,int) 显示为一个重要的热点,这并没有什么坏处。

要评估这种情况,重要的是要了解不是临时对象的数量会使重复的String.concat 变得昂贵。过度创建临时对象可能会火上浇油,所以如果有一个简单的选择,仍然值得避免它。但是重复调用String.concat 的问题在于,每个临时字符串实例的创建都意味着复制构成字符串内容的整个字符数据。 concat 调用您的字符串构建的次数越多,您就越接近二次时间复杂度。

StringBuilder 通过使用可变缓冲区解决了这个问题。当容量耗尽时仍然会复制它,但是通过使用一个因子来确定新容量,整体时间复杂度保持线性。 insert 的实现并没有改变这个基本原则。临时的String 实例只会导致右侧的复制,因此它只会引入一个常数因子 2 而不会改变时间复杂度。

但不要忘记insert 原则上承载缓冲区后续字符数据的副本。如果您在缓冲区的开头重复插入,则无论底层实现进行了多少优化,您都将转向二次时间复杂度。因此,如果您过度执行此操作,那么无论如何,2 的因子都会变得可以忽略不计。

【讨论】:

  • 我工作的环境中任何 gc 分配都是不可接受的,即使有更多的 CPU 工作要做。所以插入方法是不可用的。我想我必须做一些 hack 才能获得类似的工作 gc 免费。
  • 好吧,你知道,如果容量用完,无论如何都会有分配。另一方面,如果您可以预测正确的初始容量,您还应该能够重写操作以使用append(可能还有用于后续内容的第二个缓冲区)。然后,您不仅可以避免分配,还可以降低复制成本。如果复制成本对您来说不重要,您可以像使用secondary.append(42); primary.insert(offset, secondary); secondary.setLength(0); secondary.append(101); primary.insert(offset, secondary); secondary.setLength(0); 等一样简单地避免分配。
  • 这基本上就是我所做的,尽管使用附加重载之一仅插入初始字符串的一部分,附加插入,然后附加字符串的其余部分。用它来制作一种方便的无 GC 格式化文本的方式。
  • 你的意思是像builder.append(original, 0, pos).append(itemToInsert).append(original, pos, original.length()).toString()?这比使用 insert 更好,甚至在 CPU 方面也是如此。
  • 是的,这基本上就是我所做的。到目前为止,它就像一个魅力。
猜你喜欢
  • 2021-02-23
  • 1970-01-01
  • 2016-03-21
  • 1970-01-01
  • 1970-01-01
  • 2013-03-17
  • 2012-03-04
  • 1970-01-01
  • 2022-01-06
相关资源
最近更新 更多