为什么 System.arraycopy 是 Java 原生的?
我很惊讶地在 Java 源代码中看到 System.arraycopy 是一个本机方法。
当然原因是因为它更快。但是代码能够使用哪些本地技巧来使其速度更快呢?
为什么不直接循环原始数组并将每个指针复制到新数组 - 当然这不是那么慢和麻烦?
I was surprised to see in the Java source that System.arraycopy is a native method.
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在本机代码中,可以使用单个
memcpy
/memmove
,而不是n个不同的复制操作。性能差异很大。In native code, it can be done with a single
memcpy
/memmove
, as opposed to n distinct copy operations. The difference in performance is substantial.它不能用Java 编写。本机代码能够忽略或消除对象数组和基元数组之间的差异。 Java 无法做到这一点,至少效率不高。
由于重叠数组所需的语义,它不能用单个
memcpy()
编写。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.
And it can't be written with a single
memcpy()
, because of the semantics required by overlapping arrays.当然,这取决于实现。
HotSpot 会将其视为“内在”并在调用站点插入代码。那是机器代码,而不是缓慢的旧 C 代码。这也意味着该方法的签名问题基本上消失了。
一个简单的复制循环非常简单,可以对其应用明显的优化。例如循环展开。到底发生什么又取决于实现。
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.
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.
在我自己的测试中,用于复制多维数组的 System.arraycopy() 比交错 for 循环快 10 到 20 倍:
这将打印:
In my own tests System.arraycopy() for copying multiple dimension arrays is 10 to 20 times faster than interleaving for loops:
This prints:
有以下几个原因:
JIT 不太可能生成与手动编写的 C 代码一样高效的低级代码。使用低级 C 可以实现许多对于通用 JIT 编译器来说几乎不可能实现的优化。
请参阅此链接,了解手写 C 实现的一些技巧和速度比较(memcpy,但原理是相同的):检查此 优化 Memcpy 提高速度
C 版本几乎独立于数组成员的类型和大小。在 java 中不可能执行相同的操作,因为无法将数组内容作为原始内存块(例如指针)获取。
There are a few reasons:
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
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).
聚会迟到了。在我看来,
System.arraycopy
是原生的,主要是因为 Java 中原始类型和类类型之间的区别。不可能编写一个方法来同时处理 int 数组和 String 数组。另外,
System.arraycopy
是在伪泛型类型之前引入的。我发现没有人链接本机实现。在 OpenJDK 中, arraycopy< /a> Java方法的实现最终调用
copy_conjoint_atomic()
使用 (while) 循环复制数组,或者如果元素类型是所谓的原始类型,则调用 C++memmove()
。Late to the party. In my opinion,
System.arraycopy
is native mainly due to the distinction between primitive types and class types in Java. It's impossible to write a single method to deal with both, say int array, and String array.Plus,
System.arraycopy
was introduced way before the pseudo generic type.I find no one links a native implementation. In OpenJDK, the arraycopy Java method is implemented to eventually call
copy_conjoint_atomic()
which copies the arrary with a (while) loop, or call C++memmove()
if the element type is so-called primitive.