System 和 Unsafe 都提供了一些重叠的功能(例如 System.arraycopy v.s _UNSAFE.copyMemory )。
System
Unsafe
System.arraycopy
_UNSAFE.copyMemory
就实现而言,看起来两者都依赖于 jni ,这是正确的语句吗?(我可以找到 unsafe.cpp ,但在JVM源代码中找不到相应的 arraycopy 实现)。
jni
arraycopy
另外,如果两者都依赖于JNI,我是否可以说两者的调用开销是相似的呢?
我知道 Unsafe 可以操作 offheap 内存,但为了比较起见,让我们在 onheap 内存上限制上下文。
offheap
onheap
谢谢你的回答。
发布于 2022-08-26 17:14:00
System.arraycopy 和 Unsafe.copyMemory 都是HotSpot的本质。这意味着,JVM在从JIT编译的方法调用这些方法时不使用JNI实现。相反,它将调用替换为特定于体系结构的优化程序集代码。
Unsafe.copyMemory
您可以在 stubGenerator_.cpp 中找到源。
stubGenerator_.cpp
以下是一个简单的JMH基准:
import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import java.util.concurrent.ThreadLocalRandom; import static one.nio.util.JavaInternals.byteArrayOffset; import static one.nio.util.JavaInternals.unsafe; @State(Scope.Benchmark) public class CopyMemory { @Param({"12", "123", "1234", "12345", "123456"}) int size; byte[] src; byte[] dst; @Setup public void setup() { src = new byte[size]; dst = new byte[size]; ThreadLocalRandom.current().nextBytes(src); @Benchmark public void systemArrayCopy() { System.arraycopy(src, 0, dst, 0, src.length); @Benchmark public void unsafeCopyMemory() { unsafe.copyMemory(src, byteArrayOffset, dst, byteArrayOffset, src.length); }
这两种方法的性能是相似的:
Benchmark (size) Mode Cnt Score Error Units CopyMemory.systemArrayCopy 12 avgt 16 5.294 ± 0.162 ns/op CopyMemory.systemArrayCopy 123 avgt 16 7.057 ± 0.406 ns/op CopyMemory.systemArrayCopy 1234 avgt 16 18.761 ± 0.492 ns/op CopyMemory.systemArrayCopy 12345 avgt 16 353.386 ± 3.627 ns/op CopyMemory.systemArrayCopy 123456 avgt 16 5234.125 ± 57.914 ns/op CopyMemory.unsafeCopyMemory 12 avgt 16 5.028 ± 0.120 ns/op CopyMemory.unsafeCopyMemory 123 avgt 16 8.055 ± 0.405 ns/op CopyMemory.unsafeCopyMemory 1234 avgt 16 19.776 ± 0.523 ns/op CopyMemory.unsafeCopyMemory 12345 avgt 16 353.549 ± 5.878 ns/op CopyMemory.unsafeCopyMemory 123456 avgt 16 5246.298 ± 65.427 ns/op
如果您使用 -prof perfasm 分析器运行这个JMH基准测试,您将看到这两个方法归结为完全相同的组装循环:
-prof perfasm
# systemArrayCopy 0.64% ↗ 0x00007fa95d4336d0: vmovdqu -0x38(%rdi,%rdx,8),%ymm0 2.81% │ 0x00007fa95d4336d6: vmovdqu %ymm0,-0x38(%rsi,%rdx,8) 5.67% │ 0x00007fa95d4336dc: vmovdqu -0x18(%rdi,%rdx,8),%ymm1 69.64% │ 0x00007fa95d4336e2: vmovdqu %ymm1,-0x18(%rsi,%rdx,8) 15.28% │ 0x00007fa95d4336e8: add $0x8,%rdx ╰ 0x00007fa95d4336ec: jle Stub::jbyte_disjoint_arraycopy+112 0x00007fa95d4336d0 # unsafeCopyMemory