【问题标题】:Java compiler doesn't optimize String concatenation automatically?Java编译器不会自动优化字符串连接?
【发布时间】:2012-07-03 21:00:05
【问题描述】:

以下Jsoup代码将容器els中所有元素的文本连接起来:

for (Element el : els)
  entireText += el.text();          

在具有约 64 个元素的容器上,每个元素包含约 1KB(整个文本总计约 64KB),这个简单的循环在典型的低端 Android 手机上大约需要 8 秒

这种缓慢的性能让我感到惊讶,因为我的印象是 Java 编译器会用 new StringBuilder(A).append(B).append(C).toString() 替换像 A + B + C 这样的表达式。

不是这样吗?

我错过了什么?

【问题讨论】:

  • 你比较了这两个选项还是只是猜测字符串连接是你问题的根本原因?
  • @home 当然我比较过。 StringBuilder 选项在 不到 1 秒内完成。
  • javac 编译器几乎不做任何优化。即使使用 JIT,它也不会对这段代码进行太多优化。开发人员需要知道这真的很有效。

标签: java performance optimization jsoup stringbuilder


【解决方案1】:

这种缓慢的表现让我感到惊讶,因为我在 Java 编译器替换 A + B + C 之类的表达式的印象 使用新的 StringBuilder(A).append(B).append(C).toString()。

于是编译器创建了代码:

for (Element el : els)
  entireText = new StringBuilder(entireText).append(el.text()).toString(); 

您需要在循环外创建 StringBuilder 并手动附加到它。

【讨论】:

  • 为什么不在每次迭代中将文本附加到 one StringBuilder 实例?你每次迭代都在做什么new StringBuilder
  • @mlk 好的。我认为Java编译器比那更聪明。
  • @alaster - 你应该创建一个 StringBuilder。我的代码是为了显示编译器在做什么而不是 OP 应该做什么。
  • @Souper:这不可能。您请求并构建一个 String 变量。编译器不能真正忽略该请求并not 构建该对象。 JVM可以从理论上检测到你从不使用String,除了构建一个新的并创建一个StringBuilder,但我怀疑任何JVM都会进行这种优化。
【解决方案2】:

这里的问题是您的第一次迭代创建了一个 1k 字符串,第二次创建了一个 2k 字符串,第三次创建了一个 3k 字符串,...

每个字符串都需要创建前一个字符串的副本。所以你的第一次迭代复制 1k 文本,第二次复制 2k,第三次复制 3k,...

因此每次迭代都比前一次慢,并且您的最后一次迭代分配一个 64k 缓冲区并复制 64k。

使用StringBuilder(如@mlk 所示)意味着您几乎只分配一次 64k(不完全,但足够接近)并且总共只复制 64k 数据(而不是 64k+63k+62k+61k+60k+ ...)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 2011-06-12
    • 2011-05-16
    • 2013-06-07
    • 2017-03-09
    相关资源
    最近更新 更多