【问题标题】:Cloning an int[] -- anyone got a faster suggestion?克隆一个 int[]——有人有更快的建议吗?
【发布时间】:2011-05-27 00:14:39
【问题描述】:

我正在查看一个配置文件,其中一个 CPU 热点是一个包含克隆最终静态 int[] 的函数。你可能会问,“为什么?”调用者使用结果作为散列过程的起点。

换句话说,代码需要做(逻辑上):

  1. 创建一个新数组
  2. 获取哈希种子(与数组大小一样多)
  3. 将值放入根据哈希种子计算的新数组中。这是一个迭代 算法,因此让种子从数组开始是有利的 - 因此从种子数组的克隆开始的想法。

在我放弃或开始编写微基准之前,我发布这个问题以防有人对 clone() 与 Arrays.copyOf 与 new 和 arraycopy 的底层内容有任何特殊的了解。

【问题讨论】:

  • 我想我在这里遗漏了一些东西,但是如果它是原始的、最终的和静态的,为什么还需要克隆?
  • 当前代码是什么样的?这也可能是 CPU 热点,因为您的程序经常调用它,并不一定意味着这部分代码是瓶颈。如果您发现 CPU 将 N% 的时间花在特定代码上,则可能是问题的最佳解决方案需要 CPU 将 N% 的时间花在此特定代码上。
  • @Casey:没有什么能阻止人们改变数组中整数的值。
  • @Casey: final 并不意味着数组变得不可变。这只是意味着您不能让该字段指向另一个不同的 int[] 数组。
  • 你在单位时间内做了多少个克隆?有多少线程?你的 int 数组有多长?

标签: java arrays performance


【解决方案1】:

Arrays.copyOf 在后台利用类似 memcopy 的指令。此外,索引越界检查较少。如果您一个一个地分配值,则每次都会进行一次“绑定”检查。

我还没有对每个建议的选项进行基准测试,但我确信Arrays.copyOf() 会比new int[] + for(...) 更快。

另一方面,我不确定Arrays.copyOf() 是否会比int[] myCopy = myOrig.clone() 更有效,因为克隆发生在原始类型数组上。编译器很可能会生成优化的字节码。只有测试才能提供明确的答案。

【讨论】:

    【解决方案2】:

    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);
    

    虽然实际上最好保留数组并在完成后重新使用它们

    【讨论】:

      【解决方案3】:

      如果代码是属于你的,那么下面的呢:

      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[] 等的代码不必每次都克隆。

      【讨论】:

        【解决方案4】:

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

        对于 1000 个或更少元素的数组大小,操作中最昂贵的部分不是复制,而是创建数组本身(即创建 2048 个元素的字节数组比将 2048 个元素复制到 System.arraycopy) 中。因此,如果您回收临时数组,您可以获得一些改进。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-01-19
          • 1970-01-01
          • 2010-10-25
          • 1970-01-01
          • 2011-12-22
          • 2015-07-02
          • 2019-01-19
          相关资源
          最近更新 更多