首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java 11字符串连接性能与java 8

Java 11字符串连接性能与java 8
EN

Stack Overflow用户
提问于 2019-03-28 19:02:28
回答 3查看 4K关注 0票数 6

有人知道为什么我在Java 8和Java 11上运行这段代码时会得到如此不同的性能吗?

在不使用任何运行时标志的情况下,与Java 8相比,此代码在Java 11下的运行速度似乎要慢得多。

代码语言:javascript
运行
复制
import java.util.Date;

public class PerformanceExperiment {
    public static volatile String s = "";

    public static void main(String[] args)
    {                         
        System.out.println("Starting performance test");
        String s1 = "STRING ONE";
        String s2 = "STRING TWO";
        long now1 = (new Date()).getTime();
        for (long i = 0; i < 1_000_000_00; i++)
        {
            s = "abc " + s1 + " def " + s2;
        }
        long now2 = (new Date()).getTime();
        System.out.println("initial block took " + (now2 - now1) + "ms");
        for (long i = 0; i < 4_000_000_00; i++)
        {
            s = "abc " + s1 + " def " + s2;
        }
        long now3 = (new Date()).getTime();
        System.out.println("Main block took " + (now3 - now2) + "ms");
    }
}

我尝试了许多命令行标记,但都没有找到与Java 8性能匹配的任何标记。

我只在Windows上进行了测试,所以它在其他操作系统上的表现可能会有所不同。

EN

回答 3

Stack Overflow用户

发布于 2019-03-28 21:03:15

我修改了你的应用程序

Netbeans profiler使用System.nanoTime()代替new Date()以获得更高的精度(有关更多信息,请参见此答案:https://stackoverflow.com/a/1776053/963076).

  • Use Netbeans profiler。

  • 循环通过10次迭代

将Netbeans 8.2与JDK 8 v181配合使用:

代码语言:javascript
运行
复制
Starting performance test 0
initial block took 3147ms
Main block took 9469ms
Starting performance test 1
initial block took 2398ms
Main block took 9601ms
Starting performance test 2
initial block took 2463ms
Main block took 9671ms
Starting performance test 3
initial block took 2464ms
Main block took 9565ms
Starting performance test 4
initial block took 2410ms
Main block took 9672ms
Starting performance test 5
initial block took 2418ms
Main block took 9598ms
Starting performance test 6
initial block took 2384ms
Main block took 9733ms
Starting performance test 7
initial block took 2402ms
Main block took 9610ms
Starting performance test 8
initial block took 2509ms
Main block took 11222ms
Starting performance test 9
initial block took 2455ms
Main block took 10661ms

剖面仪显示了这个遥测结果:

对于使用JDK 11.0.2的Netbeans 10.0:

代码语言:javascript
运行
复制
Starting performance test 0
initial block took 3760ms
Main block took 15056ms
Starting performance test 1
initial block took 3734ms
Main block took 14602ms
Starting performance test 2
initial block took 3615ms
Main block took 14762ms
Starting performance test 3
initial block took 3748ms
Main block took 14534ms
Starting performance test 4
initial block took 3628ms
Main block took 14759ms
Starting performance test 5
initial block took 3625ms
Main block took 14959ms
Starting performance test 6
initial block took 3987ms
Main block took 14967ms
Starting performance test 7
initial block took 3803ms
Main block took 14701ms
Starting performance test 8
initial block took 3599ms
Main block took 14762ms
Starting performance test 9
initial block took 3627ms
Main block took 14434ms

我的结论是: JDK 11正在做更多的工作来提高内存效率。请注意,使用JDK11时,垃圾收集器中的“幸存世代”数量要少得多,内存使用量和易失性也要少得多。权衡似乎是在速度上,但速度的差异小于内存使用的差异。

票数 7
EN

Stack Overflow用户

发布于 2019-04-01 22:29:38

TL;DR:需要更好的基准测试,更好的设置来控制不同版本之间的差异,等等。大多数基准测试问题都可以通过使用JMH来解决。当前的测试行为似乎可以通过可疑的基准测试方法和默认GC的变化来解释。

请考虑以下内容:

代码语言:javascript
运行
复制
public class PerformanceExperiment {
    public static volatile String s = "";

    public static void main(String[] args) {
        for (int c = 0; c < 5; c++) {
            test();
        }
    }

    public static void test() {
        String s1 = "STRING ONE";
        String s2 = "STRING TWO";
        long time1 = System.currentTimeMillis();
        for (long i = 0; i < 4_000_000_00; i++) {
            s = "abc " + s1 + " def " + s2;
        }
        long time2 = System.currentTimeMillis();
        System.out.println("Main block took " + (time2 - time1) + "ms");
    }
}

首先,它使用了更方便的计时。然后,它测量相同的字节码块,而原始测试预热“初始码”,然后继续测量绝对冷的字节码块。

然后,即时编译将命中该方法,并且您希望再次输入该方法以运行优化的代码,否则您将运行中间的“栈上替换”代码--您可以通过调用test的外部迭代来完成此操作。最重要的是,您希望多次输入以捕获最优化的版本。

而且,由于测试分配了大量内存,因此您需要确定堆的大小。

所以,这里:

代码语言:javascript
运行
复制
$ ~/Install/jdk8u191-rh/bin/javac PerformanceExperiment.java
$ ~/Install/jdk8u191-rh/bin/java -Xms2g -Xmx2g PerformanceExperiment
Main block took 10024ms
Main block took 9768ms
Main block took 7249ms
Main block took 7235ms
Main block took 7205ms

在同一字节码上,这里的...and是11.0.2:

代码语言:javascript
运行
复制
$ ~/Install/jdk11.0.2/bin/java -Xms2g -Xmx2g PerformanceExperiment
Main block took 9775ms
Main block took 10825ms
Main block took 8635ms
Main block took 8616ms
Main block took 8622ms

这里的...and是带有匹配GC的11.0.2 (9+将缺省值更改为带有JEP 248的G1 ):

代码语言:javascript
运行
复制
$ ~/Install/jdk11.0.2/bin/java -Xms2g -Xmx2g -XX:+UseParallelGC PerformanceExperiment
Main block took 9281ms
Main block took 9129ms
Main block took 6725ms
Main block took 6688ms
Main block took 6684ms

最重要的是,在每个微小的迭代中都有volatile商店,这花费了相当多的成本,可能会扭曲基准。

还有带有本地化字符串连接(JEP 280)interaction、线程本地握手(JEP 312)和其他VM修复,但您可能只有在编译过去的target=8时才会看到这一点,这超出了本练习的范围。

票数 6
EN

Stack Overflow用户

发布于 2019-04-01 17:28:19

这现在已经被确认为JDK中的一个错误:

https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8221733

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55395958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档