Pertanyaan Mengapa System.arraycopy asli di Jawa?


Saya terkejut melihat di sumber Java bahwa System.arraycopy adalah metode asli.

Tentu saja alasannya adalah karena lebih cepat. Tapi trik asli apa yang bisa digunakan oleh kode yang membuatnya lebih cepat?

Mengapa tidak hanya loop di atas array asli dan salin setiap pointer ke array baru - tentunya ini tidak terlalu lambat dan rumit?


76
2018-05-05 10:01


asal


Jawaban:


Dalam kode asli, itu bisa dilakukan dengan satu memcpy / memmove, sebagai lawan n operasi salinan yang berbeda. Perbedaan dalam kinerjanya cukup besar.


72
2018-05-05 10:04



Itu tidak bisa ditulis di Java. Kode asli mampu mengabaikan atau menghilangkan perbedaan antara array Object dan array primitif. Java tidak bisa melakukan itu, paling tidak tidak efisien.

Dan itu tidak bisa ditulis dengan satu memcpy(), karena semantik yang diperlukan oleh susunan yang tumpang tindih.


15
2018-05-05 10:09



Hal ini tentu saja tergantung pada implementasinya.

HotSpot akan memperlakukannya sebagai "intrinsik" dan memasukkan kode di situs panggilan. Itu adalah kode mesin, bukan kode C lambat yang lama. Ini juga berarti masalah dengan tanda tangan metode sebagian besar hilang.

Salinan loop sederhana cukup sederhana sehingga optimisasi yang jelas dapat diterapkan untuk itu. Misalnya loop membuka gulungan. Tepatnya apa yang terjadi adalah lagi implementasi tergantung.


9
2018-05-05 10:17



Dalam pengujian saya sendiri System.arraycopy () untuk menyalin beberapa dimensi array adalah 10 hingga 20 kali lebih cepat daripada interleaving for loop:

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

Cetakan ini:

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

4
2017-11-28 14:44



Ada beberapa alasan:

  1. JIT tidak mungkin menghasilkan kode tingkat rendah yang efisien sebagai kode C yang ditulis secara manual. Menggunakan low level C dapat mengaktifkan banyak optimasi yang hampir tidak mungkin dilakukan untuk compiler JIT generik.

    Lihat tautan ini untuk beberapa trik dan perbandingan kecepatan dari implementasi C tulisan tangan (memcpy, tetapi prinsipnya sama): Periksa ini Mengoptimalkan Memcpy meningkatkan kecepatan

  2. Versi C cukup banyak tergantung pada jenis dan ukuran anggota array. Tidak mungkin melakukan hal yang sama di java karena tidak ada cara untuk mendapatkan isi array sebagai blok baku memori (misalnya pointer).


3
2018-05-05 10:15