为什么Java 7中的StringBuilder#append(int)比Java 8中的快?

为什么Java 7中的StringBuilder#append(int)比Java 8中的快?,第1张

为什么Java 7中的StringBuilder#append(int)比Java 8中的快?

TL; DR: 副作用

append
显然破坏了StringConcat优化

原始问题和更新中的分析非常好!

为了完整起见,以下是一些缺少的步骤:

  • -XX:+PrintInlining
    同时参阅7u55和8u5。在7u55中,您将看到以下内容:
 @ 16   org.sample.IntStr::inlineSideEffect (25 bytes)   force inline

by CompilerOracle
@ 4 java.lang.StringBuilder:: (7 bytes) inline (hot)
@ 18 java.lang.StringBuilder::append (8 bytes) already compiled
into a big method
@ 21 java.lang.StringBuilder::toString (17 bytes) inline (hot)

…在8u5中:

 @ 16   org.sample.IntStr::inlineSideEffect (25 bytes)   force inline

by CompilerOracle
@ 4 java.lang.StringBuilder:: (7 bytes) inline (hot)
@ 3 java.lang.AbstractStringBuilder:: (12 bytes) inline
(hot)
@ 1 java.lang.Object:: (1 bytes) inline (hot)
@ 18 java.lang.StringBuilder::append (8 bytes) inline (hot)
@ 2 java.lang.AbstractStringBuilder::append (62 bytes) already
compiled into a big method
@ 21 java.lang.StringBuilder::toString (17 bytes) inline (hot)
@ 13 java.lang.String:: (62 bytes) inline (hot)
@ 1 java.lang.Object:: (1 bytes) inline (hot)
@ 55 java.util.Arrays::copyOfRange (63 bytes) inline (hot)
@ 54 java.lang.Math::min (11 bytes) (intrinsic)
@ 57 java.lang.System::arraycopy (0 bytes) (intrinsic)

您可能会注意到7u55版本较浅,并且在

StringBuilder
方法之后似乎什么也没叫-这很好地表明了字符串优化已经生效。确实,如果您使用来运行7u55
-XX:-OptimizeStringConcat
,子调用将重新出现,并且性能将下降到8u5级别。

  • 好的,因此我们需要弄清楚为什么8u5没有进行相同的优化。使用Grep http://hg.openjdk.java.net/jdk9/jdk9/hotspot查找“ StringBuilder”,以了解VM在哪里处理StringConcat优化。这将带您进入

    src/share/vm/opto/stringopts.cpp

  • hg log src/share/vm/opto/stringopts.cpp
    找出那里的最新变化。候选人之一是:

changeset:   5493:90abdd727e64user:        iveresovdate:        Wed Oct 16 11:13:15 2013 -0700summary:     8009303: Tiered: incorrect results in VM tests

stringconcat…

  • 在OpenJDK邮件列表上查找审阅线程(很容易用Google搜索更改集摘要):http : //mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2013-October/012084.html

  • 现货“字符串连接优化,将模式折叠成单个字符串分配并直接形成结果。在优化代码中可能发生的所有可能的取消 *** 作都从头开始重新启动该模式(从StringBuffer分配开始) 。 这意味着,整个模式必须我没有副作用。 “尤里卡?

  • 写下对比基准

@Fork(5)@Warmup(iterations = 5)@Measurement(iterations = 5)@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)@State(Scope.Benchmark)public class IntStr {    private int counter;
    @GenerateMicroBenchmark    public String inlineSideEffect() {        return new StringBuilder().append(counter++).toString();    }    @GenerateMicroBenchmark    public String spliceSideEffect() {        int cnt = counter++;        return new StringBuilder().append(cnt).toString();    }}
  • 在JDK 7u55上进行测量,看到内联/拼接副作用的性能相同:
Benchmark Mode   Samples         Mean   Mean

error Units
o.s.IntStr.inlineSideEffect avgt 25 65.460 1.747
ns/op
o.s.IntStr.spliceSideEffect avgt 25 64.414 1.323
ns/op

  • 在JDK 8u5上对其进行测量,看到内联效果会导致性能下降:
Benchmark Mode   Samples         Mean   Mean

error Units
o.s.IntStr.inlineSideEffect avgt 25 84.953 2.274
ns/op
o.s.IntStr.spliceSideEffect avgt 25 65.386 1.194
ns/op

  • 提交错误报告(https://bugs.openjdk.java.net/browse/JDK-8043677),以与VM人员讨论此行为。原始修复的基本原理是坚如磐石,但是有趣的是,如果我们能够/应该在这种琐碎的情况下恢复这种优化。

  • ???

  • 利润。

是的,我应该发布基准的结果,该基准将增量从

StringBuilder
链中移出,并在整个链之前进行。同样,切换到平均时间和ns / op。这是JDK
7u55:

BenchmarkMode   Samples         Mean   Mean error

Units
o.s.IntStr.integerToString avgt 25 153.805 1.093
ns/op
o.s.IntStr.stringBuilder0 avgt 25 128.284 6.797
ns/op
o.s.IntStr.stringBuilder1 avgt 25 131.524 3.116
ns/op
o.s.IntStr.stringBuilder2 avgt 25 254.384 9.204
ns/op
o.s.IntStr.stringFormat avgt 25 2302.501 103.032
ns/op

这是8u5:

BenchmarkMode   Samples         Mean   Mean error

Units
o.s.IntStr.integerToString avgt 25 153.032 3.295
ns/op
o.s.IntStr.stringBuilder0 avgt 25 127.796 1.158
ns/op
o.s.IntStr.stringBuilder1 avgt 25 131.585 1.137
ns/op
o.s.IntStr.stringBuilder2 avgt 25 250.980 2.773
ns/op
o.s.IntStr.stringFormat avgt 25 2123.706 25.105
ns/op

stringFormat
实际上在8u5中要快一些,其他所有测试都相同。这巩固了原问题中主要罪魁祸首中SB链副作用断裂的假说。



欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5489547.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-12
下一篇2022-12-12

发表评论

登录后才能评论

评论列表(0条)

    保存