Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么System.arraycopy是Java本机的?_Java_Native_Arrays - Fatal编程技术网

为什么System.arraycopy是Java本机的?

为什么System.arraycopy是Java本机的?,java,native,arrays,Java,Native,Arrays,我很惊讶地在Java源代码中看到System.arraycopy是一个本机方法 当然原因是因为它更快。但是,代码能够采用哪些本机技巧使其更快 为什么不直接在原始数组上循环并将每个指针复制到新数组上呢?当然这并不是那么慢和麻烦吗?在本机代码中,可以使用单个memcpy/,而不是n个不同的复制操作。性能上的差异很大。它不能用Java编写。本机代码能够忽略或消除对象数组和原语数组之间的差异。Java无法做到这一点,至少效率不高 由于重叠数组需要语义,因此不能使用单个memcpy()来编写它。有几个原因

我很惊讶地在Java源代码中看到System.arraycopy是一个本机方法

当然原因是因为它更快。但是,代码能够采用哪些本机技巧使其更快


为什么不直接在原始数组上循环并将每个指针复制到新数组上呢?当然这并不是那么慢和麻烦吗?

在本机代码中,可以使用单个
memcpy
/,而不是n个不同的复制操作。性能上的差异很大。

它不能用Java编写。本机代码能够忽略或消除对象数组和原语数组之间的差异。Java无法做到这一点,至少效率不高


由于重叠数组需要语义,因此不能使用单个
memcpy()
来编写它。

有几个原因:

  • JIT不可能生成与手动编写的C代码一样高效的低级代码。使用低级C可以实现许多优化,而对于通用JIT编译器来说,这些优化几乎是不可能实现的

    请参阅此链接,了解手写C实现的一些技巧和速度比较(memcpy,但原理相同):检查此链接

  • C版本几乎与数组成员的类型和大小无关。在java中不可能这样做,因为无法将数组内容作为原始内存块(例如指针)获取


  • 当然,它取决于实现

    HotSpot会将其视为“内在的”,并在调用站点插入代码。这是机器代码,不是很慢的旧C代码。这也意味着方法签名的问题在很大程度上消失了


    简单的复制循环足够简单,可以对其应用明显的优化。例如,循环展开。确切地说,发生的情况同样取决于实现。

    在我自己的测试系统中。用于复制多维数组的arraycopy()比用于循环的交错快10到20倍:

    float[][] foo = mLoadMillionsOfPoints(); // result is a float[1200000][9]
    float[][] fooCpy = new float[foo.length][foo[0].length];
    long lTime = System.currentTimeMillis();
    System.arraycopy(foo, 0, fooCpy, 0, foo.length);
    System.out.println("native duration: " + (System.currentTimeMillis() - lTime) + " ms");
    lTime = System.currentTimeMillis();
    
    for (int i = 0; i < foo.length; i++)
    {
        for (int j = 0; j < foo[0].length; j++)
        {
            fooCpy[i][j] = foo[i][j];
        }
    }
    System.out.println("System.arraycopy() duration: " + (System.currentTimeMillis() - lTime) + " ms");
    for (int i = 0; i < foo.length; i++)
    {
        for (int j = 0; j < foo[0].length; j++)
        {
            if (fooCpy[i][j] != foo[i][j])
            {
                System.err.println("ERROR at " + i + ", " + j);
            }
        }
    }
    

    好吧,那么
    memmove
    。虽然我不认为这在这个问题的上下文中有多大区别。也不是memmove(),请参阅@Stephen C对另一个答案的评论。已经看到了,因为这恰好是我自己的答案;-)不过还是要谢谢你。@Geek数组重叠了。如果源数组和目标数组相同,并且只有偏移量不同,则会仔细指定行为,并且memcpy()不符合要求。它不能用Java编写吗?难道一个人不能编写一个泛型方法来处理对象的子类,然后为每个基本类型编写一个泛型方法吗?Java代码可以得到优化。事实上,实际发生的是生成了比C更高效的机器代码。我同意,有时JIT代码会更好地进行局部优化,因为它知道在哪个处理器上运行。然而,由于它是“及时的”,它将永远无法使用所有需要更长时间才能执行的非本地优化。此外,它将永远无法匹配手工编制的C代码(这也可能会考虑处理器,并通过为特定处理器编译或某种运行时检查部分否定JIT优势)。我认为Sun JIT编译器团队会对其中的许多观点提出质疑。例如,我相信HotSpot会进行全局优化,以消除不必要的方法调度,JIT没有理由不能生成特定于处理器的代码。还有一点是,JIT编译器可以根据当前应用程序运行的执行行为进行分支优化。@Stephen C-关于分支优化,aldough您还可以使用C/C++编译器执行静态性能评测,以达到类似的效果。我还认为hotspot有两种操作模式——桌面应用程序不会使用所有可用的优化来实现合理的启动时间,而服务器应用程序将得到更积极的优化。总而言之,您获得了一些优势,但也失去了一些。System.arrayCopy不是用C实现的,这使得这个答案无效。实际上,只有
    arrayCopy
    的一些子类可以用
    memcpy
    /
    memmove
    实现。其他需要为每个元素复制一个运行时类型检查。@史蒂芬C,有趣的是,为什么?@ p t t o or k -考虑从<代码>对象[][COD] >用<代码>字符串< /COD>对象填充到<代码>字符串[]/COD>。参见Peter的最后一段,Object[]和byte[]+char[]是最常被复制的,它们都不需要显式的类型检查。编译器足够聪明,除非需要,否则不会进行检查,事实上99.9%的情况下,它不是。有趣的是,小尺寸的拷贝(小于缓存线)占主导地位,所以“memcpy”对于小尺寸的东西来说速度非常重要。@jainilvachhani
    memcpy
    memmove
    都是O(n),但是由于f.e.simd优化,它们的速度快了几倍,所以你可以说它们是O(n/x),其中x依赖于这些函数中使用的优化这是一个非常好的答案:),特别是提到内部函数。没有他们,简单的迭代可能会更快,因为不管怎么说,JIT通常都会展开它,即使这个问题很老,只是为了记录:这不是一个公平的基准(更不用说这样的基准一开始是否有意义了)
    System.arraycopy执行浅复制(仅复制对内部
    float[]
    s的引用),而嵌套的
    for
    -循环执行深复制(
    float
    by
    float
    )。对
    fooCpy[i][j]
    的更改将通过
    System.arraycopy
    反映在
    foo
    中,但不会对
    -循环使用嵌套的
    System.arraycopy() duration: 1 ms
    loop duration: 16 ms