将Java数组中任意元素设置为NULL的最快方法是什么?

 2023-01-19    389  

问题描述

我知道我可以简单地从start迭代到end并清除那些单元,但我想知道它是否可以更快地使用(也许使用jni-ed System.arrayCopy)?

推荐答案

如果我正确地完成了,则需要将数组取消,或一个包含对象引用的数组的子端,以使它们符合GC的资格.并且您有一个常规的Java数组,该数组将数据存储在Heap中.

将Java数组中任意元素设置为NULL的最快方法是什么?

回答您的问题,System.arrayCopy是将阵列取消阵列的最快方法.不过,它的内存比Arrays.fill差,因为您必须分配两倍的内存才能在最坏情况下保存参考,以便可以从中复制一系列null.虽然,如果您需要将数组完全删除,那么更快的速度就是创建一个新的空数组(例如new Object[desiredLength]),然后替换要使用它的阵列.

Unsafe,DirectByteBuffer,DirectLongBuffer实现在幼稚的直接实现中没有提供任何性能增益(即,如果您只用Array替换DirectByteBuffer或DirectByteBuffer或Unsafe).它们也慢于散装System.arrayCopy.由于这些实现与Java Array无关,因此无论如何它们都不在您的问题范围.

这是我的JMH基准(完整的基准代码可用 via via via via via via via via giist ) C14>根据@apangin注释;并包括ByteBuffer.put(long[] src, int srcOffset, int longCount)根据 @jan-chaefer;以及按照 @scott-carey的相当于Arrays.fill的循环,以检查Arrays.fill是否可能是JDK 8中的固有性.

@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void arrayFill() {
    Arrays.fill(objectHolderForFill, null);
}

@Benchmark
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void arrayFillManualLoop() {
    for (int i = 0, len = objectHolderForFill.length; i < len; i++) {
        objectHolderForLoop[i] = 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);
}

这是我得到的(Java 1.8,JMH 1.13,Core i3-6100U 2.30 GHz,Win10):

100 elements
Benchmark                                       Mode      Cnt   Score   Error    Units
ArrayNullFillBench.arrayCopy                   sample  5234029  39,518 ± 0,991   ns/op
ArrayNullFillBench.directByteBufferBatch       sample  6271334  43,646 ± 1,523   ns/op
ArrayNullFillBench.directLongBufferBatch       sample  4615974  45,252 ± 2,352   ns/op
ArrayNullFillBench.arrayFill                   sample  4745406  76,997 ± 3,547   ns/op
ArrayNullFillBench.arrayFillManualLoop         sample  5549216  78,677 ± 13,013  ns/op
ArrayNullFillBench.unsafeArrayManualLoop       sample  5980381  78,811 ± 2,870   ns/op
ArrayNullFillBench.unsafeArraySetMemory        sample  5985884  85,062 ± 2,096   ns/op
ArrayNullFillBench.directLongBufferManualLoop  sample  4697023  116,242 ±  2,579  ns/op <-- wow
ArrayNullFillBench.directByteBufferManualLoop  sample  7504629  208,440 ± 10,651  ns/op <-- wow

I skipped all** the loop implementations from further tests
** - except arrayFill and arrayFillManualLoop for scale

1000 elements
Benchmark                                 Mode      Cnt    Score   Error    Units
ArrayNullFillBench.arrayCopy              sample  6780681  184,516 ± 14,036  ns/op
ArrayNullFillBench.directLongBufferBatch  sample  4018778  293,325 ± 4,074   ns/op
ArrayNullFillBench.directByteBufferBatch  sample  4063969  313,171 ± 4,861   ns/op
ArrayNullFillBench.arrayFillManualLoop    sample  6270397  543,801 ± 20,325  ns/op
ArrayNullFillBench.arrayFill              sample  6590416  548,250 ± 13,475  ns/op

10000 elements
Benchmark                                 Mode      Cnt     Score   Error    Units
ArrayNullFillBench.arrayCopy              sample  2551851  2024,543 ± 12,533  ns/op
ArrayNullFillBench.directLongBufferBatch  sample  2958517  4469,210 ± 10,376  ns/op
ArrayNullFillBench.directByteBufferBatch  sample  2892258  4526,945 ± 33,443  ns/op
ArrayNullFillBench.arrayFill              sample  2578580  5532,063 ± 20,705  ns/op
ArrayNullFillBench.arrayFillManualLoop    sample  2562569  5550,195 ± 40,666  ns/op

P.S.
说到ByteBuffer和Unsafe – 他们在您的情况下的主要好处是它们将数据存储在疑虑中,您可以实现自己的内存DeealLocation alghorithm,这比常规GC更好地涉及您的数据结构.因此,您无需将它们取消,并且可以按照您的要求进行紧凑记忆.最有可能的努力并不值得,因为比您现在拥有的更少的性能和更容易出错的代码要容易得多.

以上所述是小编给大家介绍的将Java数组中任意元素设置为NULL的最快方法是什么?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/25822.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。