JNA tampaknya sedikit lebih mudah digunakan untuk memanggil kode asli dibandingkan dengan JNI. Dalam kasus apa Anda akan menggunakan JNI melalui JNA?
JNA tampaknya sedikit lebih mudah digunakan untuk memanggil kode asli dibandingkan dengan JNI. Dalam kasus apa Anda akan menggunakan JNI melalui JNA?
Jawaban:
Ini adalah masalah yang saya temui. Mungkin masih ada lagi. Tetapi secara umum kinerjanya tidak jauh berbeda antara jna dan jni, jadi di mana pun Anda dapat menggunakan JNA, gunakanlah.
EDIT
Jawaban ini sepertinya cukup populer. Berikut beberapa tambahannya:
Jadi, saya masih percaya bahwa jika memungkinkan, lebih baik menggunakan JNA atau BridJ, dan kembali ke jni jika kinerja sangat penting, karena jika Anda perlu sering memanggil fungsi asli, kinerja yang dicapai akan terlihat.
JNIEXPORT
fungsi global . Saat ini saya menjelajahi JavaCpp sebagai opsi, yang menggunakan JNI, tetapi menurut saya vanilla JNI tidak mendukung ini. Apakah ada cara untuk memanggil fungsi anggota C ++ menggunakan vanilla JNI yang saya abaikan?
Sulit untuk menjawab pertanyaan umum seperti itu. Saya kira perbedaan yang paling jelas adalah bahwa dengan JNI, konversi tipe diimplementasikan di sisi asli dari perbatasan Java / native, sedangkan dengan JNA, konversi tipe diimplementasikan di Java. Jika Anda sudah merasa cukup nyaman dengan pemrograman dalam C dan harus mengimplementasikan sendiri beberapa kode native, saya berasumsi bahwa JNI tampaknya tidak terlalu rumit. Jika Anda seorang programmer Java dan hanya perlu memanggil pustaka asli pihak ketiga, menggunakan JNA mungkin merupakan cara termudah untuk menghindari masalah yang mungkin tidak terlalu jelas dengan JNI.
Meskipun saya tidak pernah membandingkan perbedaan apa pun, saya akan melakukannya karena desainnya, setidaknya anggaplah jenis konversi dengan JNA dalam beberapa situasi akan berkinerja lebih buruk daripada dengan JNI. Misalnya ketika mengoper array, JNA akan mengubahnya dari Java ke native di awal setiap pemanggilan fungsi dan kembali di akhir pemanggilan fungsi. Dengan JNI, Anda dapat mengontrol diri Anda sendiri saat "tampilan" native dari array dibuat, berpotensi hanya membuat tampilan dari bagian array, mempertahankan tampilan di beberapa pemanggilan fungsi dan pada akhirnya melepaskan tampilan tersebut dan memutuskan apakah Anda mau untuk menyimpan perubahan (berpotensi perlu menyalin data kembali) atau membuang perubahan (tidak perlu menyalin). Saya tahu Anda dapat menggunakan array asli di seluruh pemanggilan fungsi dengan JNA menggunakan kelas Memori, tetapi ini juga akan membutuhkan penyalinan memori, yang mungkin tidak diperlukan dengan JNI. Perbedaannya mungkin tidak relevan, tetapi jika tujuan awal Anda adalah meningkatkan kinerja aplikasi dengan menerapkan sebagian darinya dalam kode asli, menggunakan teknologi penghubung yang berkinerja lebih buruk tampaknya bukan pilihan yang paling jelas.
Itu hanya apa yang bisa saya pikirkan, meskipun saya juga bukan pengguna berat. Sepertinya Anda juga dapat menghindari JNA jika Anda menginginkan antarmuka yang lebih baik daripada yang mereka sediakan tetapi Anda dapat mengkodekannya di java.
Ngomong-ngomong, di salah satu proyek kami, kami menyimpan footprint JNI yang sangat kecil. Kami menggunakan buffer protokol untuk mewakili objek domain kami dan dengan demikian hanya memiliki satu fungsi asli untuk menjembatani Java dan C (tentu saja fungsi C akan memanggil banyak fungsi lainnya).
Ini bukan jawaban langsung dan saya tidak memiliki pengalaman dengan JNA tetapi, ketika saya melihat Proyek Menggunakan JNA dan melihat nama-nama seperti SVNKit, IntelliJ IDEA, NetBeans IDE, dll, saya cenderung percaya ini adalah perpustakaan yang cukup baik.
Sebenarnya, saya pasti berpikir saya akan menggunakan JNA daripada JNI ketika saya harus karena memang terlihat lebih sederhana daripada JNI (yang memiliki proses pengembangan yang membosankan). Sayang sekali, JNA tidak dirilis saat ini.
Jika Anda menginginkan kinerja JNI tetapi terhalang oleh kerumitannya, Anda dapat mempertimbangkan untuk menggunakan alat yang menghasilkan pengikatan JNI secara otomatis. Misalnya, JANET (penafian: Saya yang menulisnya) memungkinkan Anda untuk mencampur kode Java dan C ++ dalam satu file sumber, dan misalnya melakukan panggilan dari C ++ ke Java menggunakan sintaks Java standar. Misalnya, inilah cara Anda mencetak string C ke output standar Java:
native "C++" void printHello() {
const char* helloWorld = "Hello, World!";
`System.out.println(#$(helloWorld));`
}
JANET kemudian menerjemahkan Java yang disematkan backtick ke dalam panggilan JNI yang sesuai.
Saya sebenarnya melakukan beberapa benchmark sederhana dengan JNI dan JNA.
Seperti yang telah ditunjukkan orang lain, JNA adalah untuk kenyamanan. Anda tidak perlu mengompilasi atau menulis kode native saat menggunakan JNA. Pemuat pustaka asli JNA juga merupakan salah satu yang terbaik / termudah untuk digunakan yang pernah saya lihat. Sayangnya, tampaknya Anda tidak dapat menggunakannya untuk JNI. (Itulah mengapa saya menulis alternatif untuk System.loadLibrary () yang menggunakan konvensi jalur JNA dan mendukung pemuatan tanpa batas dari classpath (mis. Guci).)
Namun, kinerja JNA bisa jauh lebih buruk daripada JNI. Saya membuat tes yang sangat sederhana yang disebut fungsi peningkatan integer asli sederhana "return arg + 1;". Tolok ukur yang dilakukan dengan jmh menunjukkan bahwa panggilan JNI ke fungsi itu 15 kali lebih cepat daripada JNA.
Contoh yang lebih "kompleks" di mana fungsi native meringkas array integer dari 4 nilai masih menunjukkan bahwa performa JNI 3 kali lebih cepat daripada JNA. Keuntungan yang berkurang mungkin karena cara Anda mengakses array di JNI: contoh saya membuat beberapa hal dan merilisnya lagi selama setiap operasi penjumlahan.
Kode dan hasil tes dapat ditemukan di github .
Saya menyelidiki JNI dan JNA untuk perbandingan kinerja karena kami perlu memutuskan salah satu dari mereka untuk memanggil dll dalam proyek dan kami memiliki kendala waktu nyata. Hasilnya menunjukkan bahwa JNI memiliki kinerja yang lebih baik daripada JNA (sekitar 40 kali lipat). Mungkin ada trik untuk kinerja yang lebih baik di JNA tetapi sangat lambat untuk contoh sederhana.
Kecuali saya melewatkan sesuatu, bukankah perbedaan utama antara JNA vs JNI bahwa dengan JNA Anda tidak dapat memanggil kode Java dari kode native (C)?
Dalam aplikasi khusus saya, JNI terbukti jauh lebih mudah digunakan. Saya perlu membaca dan menulis aliran berkelanjutan ke dan dari port serial - dan tidak ada yang lain. Daripada mencoba mempelajari infrastruktur yang sangat terlibat di JNA, saya merasa jauh lebih mudah untuk membuat prototipe antarmuka asli di Windows dengan DLL tujuan khusus yang mengekspor hanya enam fungsi: