gpt4 book ai didi

java - 装箱与创建 1 个元素的数组

转载 作者:行者123 更新时间:2023-11-30 10:26:42 25 4
gpt4 key购买 nike

免责声明:我阅读了this article Alexey Shipilev 认为纳米基准测试是一种邪恶。但无论如何都想自己试验和理解。

我正在尝试衡量数组创建与 byte 的装箱。这是我的基准:

@Fork(1)
@Warmup(iterations = 5, timeUnit = TimeUnit.NANOSECONDS)
@Measurement(iterations = 5, timeUnit = TimeUnit.NANOSECONDS)
public class MyBenchmark {

@Benchmark
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public void arrayBenchmark(Blackhole bh) {
byte[] b = new byte[1];
b[0] = 20;
bh.consume(b);
}

@Benchmark
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public void bonxingBenchmark(Blackhole bh) {
bh.consume(new Byte((byte) 20));
}
}

我多次运行这个基准测试,出于某种原因我发现装箱比创建数组并将元素放入其中快 1.5 倍

所以我决定使用 -prof gc 运行这个基准测试。结果是这样的:

MyBenchmark.arrayBenchmark                                     avgt    5     7.751 ±    0.537   ns/op
MyBenchmark.arrayBenchmark:·gc.alloc.rate avgt 5 1966.743 ± 143.624 MB/sec
MyBenchmark.arrayBenchmark:·gc.alloc.rate.norm avgt 5 24.000 ± 0.001 B/op
MyBenchmark.arrayBenchmark:·gc.churn.PS_Eden_Space avgt 5 1966.231 ± 326.378 MB/sec
MyBenchmark.arrayBenchmark:·gc.churn.PS_Eden_Space.norm avgt 5 23.999 ± 4.148 B/op
MyBenchmark.arrayBenchmark:·gc.churn.PS_Survivor_Space avgt 5 0.042 ± 0.113 MB/sec
MyBenchmark.arrayBenchmark:·gc.churn.PS_Survivor_Space.norm avgt 5 0.001 ± 0.001 B/op
MyBenchmark.arrayBenchmark:·gc.count avgt 5 37.000 counts
MyBenchmark.arrayBenchmark:·gc.time avgt 5 48.000 ms

MyBenchmark.bonxingBenchmark avgt 5 6.123 ± 1.306 ns/op
MyBenchmark.bonxingBenchmark:·gc.alloc.rate avgt 5 1664.504 ± 370.508 MB/sec
MyBenchmark.bonxingBenchmark:·gc.alloc.rate.norm avgt 5 16.000 ± 0.001 B/op
MyBenchmark.bonxingBenchmark:·gc.churn.PS_Eden_Space avgt 5 1644.547 ± 1004.476 MB/sec
MyBenchmark.bonxingBenchmark:·gc.churn.PS_Eden_Space.norm avgt 5 15.769 ± 7.495 B/op
MyBenchmark.bonxingBenchmark:·gc.churn.PS_Survivor_Space avgt 5 0.037 ± 0.067 MB/sec
MyBenchmark.bonxingBenchmark:·gc.churn.PS_Survivor_Space.norm avgt 5 ≈ 10⁻³ B/op
MyBenchmark.bonxingBenchmark:·gc.count avgt 5 23.000 counts
MyBenchmark.bonxingBenchmark:·gc.time avgt 5 37.000 ms

正如我们所见,GCarrayBenchmark 情况下负载很重。分配率 1966 对比 1664gc-countgc-time 也不同。 我认为这是原因,但不确定

目前我不太理解这种行为。我认为在我的例子中数组分配只是意味着我们在某处分配 1 个字节。对我来说,它看起来与 Boxing 几乎相同,但实际上不同。

你能帮我理解一下吗?

最重要的是...我可以相信这个基准吗?

最佳答案

TL;DR 这是因为 Java 对象 memory layout * 和数组开销。

每个对象都有header (存储身份哈希码、锁和 gc 元信息的位置)和类指针。此外,对象的地址应对齐到 8。

假设您使用的是 x86-64 处理器, header 大小为 8 字节,类指针大小为 4 字节。Byte 中的 byte 字段占用 1 个字节 => Byte 应该占用 13 个字节,但四舍五入到对齐正好给你 16 个字节,你用-prof gc.

对于数组的计算大部分是相同的,但是数组有 4 字节的 length 字段(从技术上讲,它不是一个真正的字段,但它并不重要),它给你 8 + 4 + 4 = 16 字节用于数组,1 字节用于单字节元素,对齐为您提供 24 字节。

所以原因之一是数组只是更大的对象。

第二个原因是创建数组的代码更复杂(您可以使用 -prof perfasm-prof dtraceasm 查看生成的代码)。数组初始化需要额外存储到 length 字段,而且(我不知道为什么)JIT 生成四个 prefetchnta 指令。

所以是的,您可以部分相信它:分配单个元素的速度略微(尽管不是 x1.5 倍)。

*请注意,所有这些仅与 Hotspot 相关,其他 JVM 可能具有不同的布局。

关于java - 装箱与创建 1 个元素的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45591876/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com