java - 性能说明 : code runs faster with unused variable

标签 java multithreading performance jvm

我之前做了一些性能测试,无法解释我获得的结果。

运行下面的测试时,如果我取消注释 private final List<String> list = new ArrayList<String>();性能显着提高。在我的机器上,当该字段存在时,测试运行时间为 70-90 毫秒,而当它被注释掉时,测试运行时间为 650 毫秒。

我还注意到,如果我将打印语句更改为 System.out.println((end - start) / 1000000); ,没有变量的测试在 450-500 毫秒而不是 650 毫秒内运行。当变量存在时它没有效果。

我的问题:

  1. 考虑到我什至不使用该变量,任何人都可以解释有或没有该变量的将近 10 的因数吗?
  2. 打印语句如何改变性能(特别是因为它出现在性能测量窗口之后)?

ps:顺序运行时,3个场景(有变量、无变量、打印语句不同)均耗时260ms左右。

public class SOTest {

    private static final int ITERATIONS = 10000000;
    private static final int THREADS = 4;

    private volatile long id = 0L;
    //private final List<String> list = new ArrayList<String>();

    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(THREADS);
        final List<SOTest> objects = new ArrayList<SOTest>();
        for (int i = 0; i < THREADS; i++) {
            objects.add(new SOTest());
        }

        //warm up
        for (SOTest t : objects) {
            getRunnable(t).run();
        }

        long start = System.nanoTime();

        for (SOTest t : objects) {
            executor.submit(getRunnable(t));
        }
        executor.shutdown();
        executor.awaitTermination(10, TimeUnit.SECONDS);

        long end = System.nanoTime();
        System.out.println(objects.get(0).id + " " + (end - start) / 1000000);
    }

    public static Runnable getRunnable(final SOTest object) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < ITERATIONS; i++) {
                    object.id++;
                }
            }
        };
        return r;
    }
}

编辑

下面是 3 种场景下 10 次运行的结果:

  • 没有变量,使用短打印语句
  • 没有变量,使用长打印语句(打印其中一个对象)
  • 顺序运行(1个线程)
  • 与变量
1   657 473 261 74
2   641 501 261 78
3   651 465 259 86
4   585 462 259 78
5   639 506 259 68
6   659 477 258 72
7   653 479 259 82
8   645 486 259 72
9   650 457 259 78
10  639 487 272 79

最佳答案

清除(虚假)分享

由于内存中的布局,对象共享缓存行... 它已经被解释了很多次(甚至在这个网站上):这里是一个 good source进一步阅读。该问题适用于 C# just as much (或 C/C++)

当您通过添加注释行填充对象时,共享会减少,您会看到性能得到提升。

编辑:我错过了第二个问题:


How can that print statement change the performance (especially since it comes after the performance measurement window)?

我想预热不够,打印 GC 和编译日志,这样你就可以确定没有干扰,代码确实被编译了。 java -server 需要 10k 次迭代,最好不要全部在主循环中生成好的代码。

关于java - 性能说明 : code runs faster with unused variable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11848325/

相关文章:

java - 不同级别的logback不同文件

java - Selenium 网格: how to maximize browser window using RemoteWebDriver and ChromeDriver

java - 在应用程序启动 Java swing 之前等待光标

java - 如何判断Java代码的效率

PHP Opcode 缓存/Zend 加速和 include_once 与 require_once

java - 使用日期和时间创建日期时间

java线程似乎没有被释放

Java 线程 : Should all shared variables be Volatile ?

c++ - 如何从另一个线程调用flutter引擎方法

sql - 不一致的 SQL Server 执行计划键查找