为什么使用直接内存';数组';清除速度比通常的Java数组慢吗?
我已经建立了一个JMH基准测试来衡量什么会更快为什么使用直接内存';数组';清除速度比通常的Java数组慢吗?,java,performance,jmh,Java,Performance,Jmh,我已经建立了一个JMH基准测试来衡量什么会更快数组。用null填充,系统。arraycopy从null数组中,将DirectByteBuffer归零或将不安全的内存块归零试图回答这个问题 让我们把直接分配的内存归零的情况放在一边,讨论一下我的基准测试的结果 以下是JMH基准代码片段(),包括@apangin在原始文章中建议的unsafe.setMemory大小写、byteBuffer.put(byte[],offset,length)和longBuffer.put(long[],offset,l
数组。用null填充,系统。arraycopy
从null数组中,将DirectByteBuffer归零或将不安全的内存块归零试图回答这个问题
让我们把直接分配的内存归零的情况放在一边,讨论一下我的基准测试的结果
以下是JMH基准代码片段(),包括@apangin在原始文章中建议的unsafe.setMemory
大小写、byteBuffer.put(byte[],offset,length)
和longBuffer.put(long[],offset,length)
,如@jan schaefer所建议:
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void arrayFill() {
Arrays.fill(objectHolderForFill, null);
}
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void arrayCopy() {
System.arraycopy(nullsArray, 0, objectHolderForArrayCopy, 0, objectHolderForArrayCopy.length);
}
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void directByteBufferManualLoop() {
while (referenceHolderByteBuffer.hasRemaining()) {
referenceHolderByteBuffer.putLong(0);
}
}
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void directByteBufferBatch() {
referenceHolderByteBuffer.put(nullBytes, 0, nullBytes.length);
}
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void directLongBufferManualLoop() {
while (referenceHolderLongBuffer.hasRemaining()) {
referenceHolderLongBuffer.put(0L);
}
}
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void directLongBufferBatch() {
referenceHolderLongBuffer.put(nullLongs, 0, nullLongs.length);
}
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void unsafeArrayManualLoop() {
long addr = referenceHolderUnsafe;
long pos = 0;
for (int i = 0; i < size; i++) {
unsafe.putLong(addr + pos, 0L);
pos += 1 << 3;
}
}
@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void unsafeArraySetMemory() {
unsafe.setMemory(referenceHolderUnsafe, size*8, (byte) 0);
}
请澄清以下问题:
1. Why `unsafeArraySetMemory` is a bit but slower than `unsafeArrayManualLoop`?
2. Why directByteBuffer is 2.5X-5X slower than others?
为什么unsafeArraySetMemory比unsafeArrayManualLoop稍慢一些
我的猜测是,对于设置多个多头,它并没有得到很好的优化。它必须检查你是否有东西,不是8的倍数
为什么directByteBuffer比其他公司慢一个数量级
一个数量级大约是10倍,大约慢2.5倍。它必须对每次访问进行边界检查,并更新字段而不是局部变量
注意:我发现JVM并不总是使用不安全的循环展开代码。你可以自己试试看是否有帮助
注意:本机代码可以使用XMM 128位指令,并且越来越多地使用这种指令,这就是为什么复制速度会如此之快。对XMM指令的访问可能来自Java 10。这种比较有点不公平。在使用Array.fill
和System.arraycopy
时使用的是单个操作,但在DirectByteBuffer
案例中使用的是循环和多次调用putLong
。如果你看一下putLong
的实现,你会发现其中有很多东西,比如检查可访问性。你应该尝试使用一个批处理操作,比如put(long[]src,int-srcfostate,int-longCount)
,看看会发生什么。如果你不介意的话,我已经更正了我的帖子,删除了这个数量级
mess:-)谢谢你指出,我已经将你的asnwer标记为有用。谢谢,我也会用批处理操作添加这个例子<代码>数组。填充
在下面使用相同的循环<代码>不安全。setMemory
也是一种批处理操作。刚刚添加了您建议的案例(ByteBuffer
和LongBuffer
版本以防万一)。看起来,即使是使用DirectBuffer
的批处理操作也比System.arraycopy
慢,并且倾向于更接近数组。在更大的数组大小上填充。
1. Why `unsafeArraySetMemory` is a bit but slower than `unsafeArrayManualLoop`?
2. Why directByteBuffer is 2.5X-5X slower than others?