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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2772152/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 12:40:41  来源:igfitidea点击:

Why is System.arraycopy native in Java?

javaarraysnativearraycopy

提问by James B

I was surprised to see in the Java source that System.arraycopy is a native method.

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

Of course the reason is because it's faster. But what native tricks is the code able to employ that make it faster?

原因当然是因为它更快。但是代码能够使用哪些本地技巧来使其更快?

Why not just loop over the original array and copy each pointer to the new array - surely this isn't that slow and cumbersome?

为什么不循环遍历原始数组并将每个指针复制到新数组——当然这不是那么慢和麻烦吗?

采纳答案by Péter T?r?k

In native code, it can be done with a single memcpy/ memmove, as opposed to ndistinct copy operations. The difference in performance is substantial.

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

回答by user207421

It can't be written in Java. Native code is able to ignore or elide the difference between arrays of Object and arrays of primitives. Java can't do that, at least not efficiently.

它不能用 Java 编写。本机代码能够忽略或消除对象数组和基元数组之间的差异。Java 不能做到这一点,至少不能有效地做到这一点。

And it can'tbe written with a single memcpy(), because of the semantics required by overlapping arrays.

并且不能用单个 编写memcpy(),因为重叠数组需要语义。

回答by Hrvoje Prge?a

There are a few reasons:

有几个原因:

  1. The JIT is unlikely to generate as efficient low level code as a manually written C code. Using low level C can enable a lot of optimizations that are close to impossible to do for a generic JIT compiler.

    See this link for some tricks and speed comparisons of hand written C implementations (memcpy, but the principle is the same): Check this Optimizing Memcpy improves speed

  2. The C version is pretty much independant of the type and size of the array members. It is not possible to do the same in java since there is no way to get the array contents as a raw block of memory (eg. pointer).

  1. JIT 不太可能生成与手动编写的 C 代码一样高效的低级代码。使用低级 C 可以实现许多对于通用 JIT 编译器几乎不可能完成的优化。

    有关手写 C 实现的一些技巧和速度比较,请参阅此链接(memcpy,但原理是相同的):检查此优化 Memcpy 提高速度

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

回答by Tom Hawtin - tackline

It is, of course, implementation dependent.

当然,这取决于实现。

HotSpot will treat it as an "intrinsic" and insert code at the call site. That is machine code, not slow old C code. This also means the problems with the signature of the method largely go away.

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

A simple copy loop is simple enough that obvious optimisations can be applied to it. For instance loop unrolling. Exactly what happens is again implementation dependent.

一个简单的复制循环足够简单,可以对其应用明显的优化。例如循环展开。究竟发生了什么再次取决于实现。

回答by jumar

In my own tests System.arraycopy() for copying multiple dimension arrays is 10 to 20 times faster than interleaving for loops:

在我自己的测试中,用于复制多维数组的 System.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);
        }
    }
}

This prints:

这打印:

System.arraycopy() duration: 1 ms
loop duration: 16 ms