克隆int[] -- 有更快的建议吗?

4
我正在查看一个CPU热点函数的配置文件,其中之一是克隆一个final static int[]。你可能会问:“为什么?”因为调用者将结果用作哈希过程的起始点。
换句话说,代码需要执行以下逻辑:
  1. 创建一个新数组
  2. 获取哈希种子(与数组大小相同)
  3. 从哈希种子计算出值并将其放入新数组中。这是一个迭代算法,因此从数组开始具有种子很有优势 - 因此想到了使用种子数组的克隆体来开始。
在我放弃或开始编写微基准测试之前,我发布了这个问题,以防有人对clone()、Arrays.copyOf和只是new和arraycopy有特殊知识。

1
我觉得我在这里漏掉了什么,但如果它是一个原始的、final 和 static 的数组,为什么需要克隆它呢? - Casey
当前代码是什么样子?同时,这可能是CPU热点,因为您的程序经常调用它,这并不一定意味着代码的这部分是瓶颈。如果您发现CPU在特定代码中花费了N%的时间,那么最优解决方案可能需要CPU在此特定代码中花费N%的时间。 - matt b
@Casey:没有什么能阻止人们改变数组中int值的内容。 - StriplingWarrior
2
@Casey:final并不意味着数组变为不可变。它仅意味着你不能将该字段指向另一个不同的int[]数组。 - BoltClock
你每单位时间做多少个克隆?使用多少个线程?你的整型数组有多长? - Ron
@BoltClock 啊,是的...即使是最终的原始数组仍然是可变的,只是引用不可变。 - Casey
4个回答

5
Arrays.copyOf利用底层的memcopy指令,因此较少进行索引越界检查。如果您逐个赋值,则每次都会进行“bound”检查。
我尚未为每个建议选项进行基准测试,但我确信Arrays.copyOf()new int[] + for(...)更快。
另一方面,我不确定Arrays.copyOf()是否比int[] myCopy = myOrig.clone()更高效,因为克隆发生在原始类型数组上。编译器很可能会生成优化的字节码。只有测试才能提供最终答案。

3
"Arrays.copyOf使用System.arraycopy,但首先添加一些边界检查。"
public static int[] copyOf(int[] original,
    int newLength) 
{
        if (0 < = newLength) {
            return copyOfRange(original, 0, newLength);
        }
        throw new NegativeArraySizeException();
}


public static int[] copyOfRange(int[] original,
    int start,
    int end) 
{
        if (start < = end) {
            if (original.length  >= start && 0 < = start) {
                int length = end - start;
                int copyLength = Math.min(length, original.length - start);
                int[] copy = new int[length];
                System.arraycopy(original, start, copy, 0, copyLength);
                return copy;
            }
            throw new ArrayIndexOutOfBoundsException();
        }
        throw new IllegalArgumentException();
}

我从http://www.docjar.com/docs/api/java/util/Arrays.html获取了这个,所以使用它可能比Arrays.copyOf稍微好一点。
int[] newone = new int[orig.length];
System.arraycopy(orig, 0, newone , 0, orig.length);

虽然最好在完成使用后保留数组并重复利用它们。

0
如果这段代码是你的,那么可以考虑以下做法:
public final class ReadOnlyIntArray {
  private final int[] _contents;

  public ReadOnlyIntArray(int[] data) {
    _contents = (int[]) data.clone();
  }

  public int get(int index) {
    return _contents[index];
  }
}

final static内容保留在其中之一,并返回该对象而不是int[]。强制消费者进行克隆,如果他们做出任何破坏性的操作。

我经常觉得这种构造应该是java.lang中的核心构造之一,这将允许返回Class[]Method[]等代码不必每次都进行克隆。


0

在Java 1.6/1.7 x86客户端VM中,对原始类型数组使用clone()比使用new []System.arraycopy组合慢约50%,但在x64服务器VM中速度大致相同。

对于少于几千个元素的数组大小,最昂贵的部分不是复制操作,而是数组本身的创建(即创建2048个元素的字节数组所需的时间比使用System.arraycopy将2048个元素复制到其中要长3倍)。因此,如果您回收临时数组,则可以获得一些改进。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接