为什么 System.arraycopy 是 Java 原生的?

发布于 2024-08-31 01:26:33 字数 142 浏览 3 评论 0原文

我很惊讶地在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

各空 2024-09-07 01:26:33

在本机代码中,可以使用单个 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.

寄居者 2024-09-07 01:26:33

它不能用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.

|煩躁 2024-09-07 01:26:33

当然,这取决于实现。

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.

凉城 2024-09-07 01:26:33

在我自己的测试中,用于复制多维数组的 System.arraycopy() 比交错 for 循环快 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);
        }
    }
}

这将打印:

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

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

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
雪落纷纷 2024-09-07 01:26:33

有以下几个原因:

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

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

  2. C 版本几乎独立于数组成员的类型和大小。在 java 中不可能执行相同的操作,因为无法将数组内容作为原始内存块(例如指针)获取。

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

君勿笑 2024-09-07 01:26:33

聚会迟到了。在我看来,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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文