为什么 运行 单线程 Java 程序会导致许多内核处于活动状态?

Why does running a single threaded Java program result in many cores active?

我正在对从 Object 转换为数据类型的总延迟进行基准测试。但是我遇到了 Java 集合的一个非常奇怪的行为,在本例中是 List.

List<Long> data = new ArrayList<>();
int SIZE = 50_000_000;

long currentTime = System.currentTimeMillis();
for (int i = 0; i < SIZE; i++) {
    data.add(currentTime++);
}

当 运行 上述代码 CPU 在我的 Intel i5 8250u(4 核)上的利用率 CPU 利用率为 100% 运行 在 IntelliJ Idea 上。所以我认为这可能是因为 IntelliJ,因此我将代码移至具有 20 个内核的 Azure VM (运行 CentOS 7.4),令我惊讶的是,这段代码最终消耗了 1500% CPU(来自 top 命令的结果)是 15 个核心。

我无法理解的是:单线程Java程序代码如何消耗超过1个内核?

EDIT:

重现步骤:

运行上面的代码。

机器配置:

笔记本电脑:4 核 16Gb 内存,Oracle Java 1.8_161

Azure VM:20 核 148GB RAM,Oracle Java 1.8_161

笔记本电脑上 JVisualVM 的输出:

您的测试只分配内存。所以它很快就耗尽了初始堆内存,导致 Full GC 运行。然后堆增加,但很快又被填满,导致另一次 Full GC 等。

$ java -XX:+PrintGC Test
[GC (Allocation Failure)  27648K->20757K(104448K), 0.0296779 secs]
[GC (Allocation Failure)  48405K->40538K(132096K), 0.0293287 secs]
[GC (Allocation Failure)  83084K->82453K(138752K), 0.0615143 secs]
[Full GC (Ergonomics)  82453K->75113K(225792K), 0.5392036 secs]
[GC (Allocation Failure)  124981K->139346K(254464K), 0.0563272 secs]
[Full GC (Ergonomics)  139346K->112504K(353792K), 0.5240216 secs]
[GC (Allocation Failure)  185709K->208841K(380416K), 0.0864858 secs]
[Full GC (Ergonomics)  208841K->168513K(512512K), 0.9035611 secs]
...

因此,您观察到的是一系列长的 Full GC 周期。 JDK8默认的垃圾收集器是Parallel,并行GC线程数等于CPU个数。

如果你运行async-profiler处于线程模式(-t),你会发现几乎所有CPU时间都花在了运行垃圾上多线程收集。