【问题标题】:JVM - Speed performance issue [duplicate]JVM - 速度性能问题 [重复]
【发布时间】:2016-06-17 08:43:00
【问题描述】:

鉴于下面的完整源代码,请解释为什么在 Eclipse 中每次执行此程序都会导致do1() 中的timedo2() 中的time 大2~3 毫秒。

JVM 是否需要“预热”?

import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

public class Question {
    public static void main(String[] args) {
        do1();
        do2();
    }

    public static void do1() {
        O obj = new O();
        Thread t = new Thread(() -> IntStream.range(0, 100000)
                    .forEach(e -> obj.incrementN()));

        long start = System.currentTimeMillis();

        t.start();

        try {
            t.join();
        } catch (InterruptedException e1) {

        }

        float time = (System.currentTimeMillis()-start)/1000F;

        System.out.println(time);
        System.out.println(obj);
        System.out.println();
    }

    public static void do2() {
        O obj = new O();
        Thread t = new Thread(() -> IntStream.range(0, 100000)
                    .forEach(e -> obj.incrementN()));

        long start = System.currentTimeMillis();

        t.start();

        try {
            t.join();
        } catch (InterruptedException e1) {

        }

        float time = (System.currentTimeMillis()-start)/1000F;

        System.out.println(time);
        System.out.println(obj);
    }
}

class O {
    private AtomicInteger n = new AtomicInteger(0);

    public void incrementN() {
        n.getAndIncrement();
    }

    @Override
    public String toString() {
        return ""+n.get();
    }
}

样本输出:

0.003
100000

0.001
100000

【问题讨论】:

  • 如果你这样做会更准确,比如说一千次,然后取平均结果。这可能只是随机性。
  • 是的,JVM 需要预热,因为大量使用的代码通过 JIT 系统编译为本机代码。
  • 它只是一次结果,平均可以给出更准确的结果。它可以是 O 类的加载时间,在 do1() 中完成一次,然后在 do2() 中不花费时间。
  • 我已经多次运行这个程序,do2() 中的time 变量总是小于do1() 中的time 变量。如果do1()do2() 被放置在main() 下的循环中,那么是的,所有结果都大约为1 ms,除了第一个或两个给出2~4 ms 的结果。 @Gurpreet Singh 时间计算在 new O() 之后开始,不确定这是否重要。

标签: java eclipse multithreading performance jvm


【解决方案1】:

这确实是一个太短的时间跨度,无法真正确定导致 do1() 执行时间比 do2() 长的原因。

一些因素可能是:

  • 垃圾收集器开始工作(例如,您的 o 和 t 对象已创建,指向它们的内存位置(在堆栈上)的指针在离开方法 do1() 时被销毁,但内存本身由垃圾收集器)

  • Eclipse 做一些介于两者之间的分析工作(测量变量、时间等)

  • 正如您所建议的,JVM 也可以做一些预热工作。

  • 不幸的 CPU 调度。无论出于何种原因,do1() 可能比 do2() 获得更多的 CPU 时间

您可以在调用 do1()(或 sleep)之前做一些事情,然后调用 do1(),然后再次等待并调用 do2() 并再次测量。或者你可以增加 do1() 和 do2() 消耗的时间。

另外,你的 do1() 和 do2() 方法(除了 do1() 中的 name 和 println 之外)完全相同,那么当你只调用 do1() 2 次时会发生什么?

【讨论】:

    猜你喜欢
    • 2012-07-23
    • 2018-05-18
    • 2012-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    • 2018-05-11
    • 2023-03-29
    相关资源
    最近更新 更多