为什么使用直接内存';数组';清除速度比通常的Java数组慢吗?

为什么使用直接内存';数组';清除速度比通常的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

我已经建立了一个JMH基准测试来衡量什么会更快
数组。用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?