【发布时间】:2021-10-05 18:26:33
【问题描述】:
我正在对从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++);
}
在我的 Intel i5 8250u(4 核)上运行上述代码时,CPU 利用率在 IntelliJ Idea 上运行时为 100%。所以我认为这可能是因为 IntelliJ,因此我将代码移动到具有 20 个内核的 Azure VM(运行 CentOS 7.4),令我惊讶的是,这段代码最终消耗了 1500% CPU(结果来自top 命令)是 15 核。
我无法理解的是:单线程 Java 程序代码如何消耗超过 1 个内核?
编辑:
复制步骤:
运行上面的代码。
机器配置:
笔记本电脑:4 核 16Gb RAM,Oracle Java 1.8_161
Azure 虚拟机:20 核 148GB RAM,Oracle Java 1.8_161
笔记本电脑上 JVisualVM 的输出:
【问题讨论】:
-
因为 JVM 本身在实际 Java 代码之外还有一些工作要做(包括垃圾收集和 JIT 编译热循环),但其中一些开销可以并行化。当 ArrayList 必须重新分配时,甚至可能并行化 memcpy。
-
但是考虑到代码的简单性,1500% 已经很多了。
-
是的,15 核是我所期望的更多线程级并行性,对 JVM 进行分析并查看它在哪里花费了所有 CPU 时间可能会很有趣。 (例如
perf record/perf report)。 JVM 本身是提前编译的,并且对于分析工具来说处理起来相对简单,除了它的 JIT 编译的客户代码块。 -
我想也许你得到了反对票,因为它提出了一个复杂的问题,但它没有足够的细节来真正调查这个问题。您必须描述更多关于如何完成测量、测量记录以及可用于重现它们的命令。
-
你在 CentOS 系统上使用的是什么 JVM?它与您的桌面不同吗?
标签: java multithreading performance jvm benchmarking