Mesin Virtual Java dan CLR

140

Sebagai semacam tindak lanjut dari pertanyaan yang disebut Perbedaan antara MSIL dan bytecode Java? , apa perbedaan (kesamaan) atau kesamaan dalam cara kerja Mesin Virtual Java versus cara.NET Framework Common Language Runtime (CLR) berfungsi?

Juga, adalah Kerangka NET CLR "mesin virtual" atau tidak memiliki atribut mesin virtual?

Frank V
sumber
Nah, jika Anda membandingkan suka dan suka, Anda harus menulis ulang pertanyaan sebagai perbedaan antara VM dan CLR (Common Language Runtime), yang merupakan analog langsung ke VM.
cletus

Jawaban:

278

Ada banyak kesamaan antara kedua implementasi (dan menurut saya: ya, mereka berdua "mesin virtual").

Untuk satu hal, keduanya VM berbasis stack, tanpa gagasan "register" seperti yang biasa kita lihat di CPU modern seperti x86 atau PowerPC. Evaluasi semua ekspresi ((1 + 1) / 2) dilakukan dengan mendorong operan ke "tumpukan" dan kemudian mengeluarkan operan tersebut dari tumpukan kapan pun instruksi (tambah, bagi, dll) perlu mengonsumsi operan tersebut. Setiap instruksi mendorong hasilnya kembali ke tumpukan.

Ini adalah cara yang mudah untuk mengimplementasikan mesin virtual, karena hampir semua CPU di dunia memiliki setumpuk, tetapi jumlah register sering berbeda (dan beberapa register memiliki tujuan khusus, dan setiap instruksi mengharapkan operandnya dalam register yang berbeda, dll. ).

Jadi, jika Anda akan memodelkan mesin abstrak, model berbasis stack murni adalah cara yang cukup baik untuk dilakukan.

Tentu saja, mesin nyata tidak beroperasi seperti itu. Jadi kompiler JIT bertanggung jawab untuk melakukan "enregistrasi" dari operasi bytecode, pada dasarnya menjadwalkan register CPU aktual untuk berisi operan dan hasil bila memungkinkan.

Jadi, saya pikir itu adalah salah satu kesamaan terbesar antara CLR dan JVM.

Adapun perbedaan ...

Satu perbedaan yang menarik antara kedua implementasi adalah bahwa CLR mencakup instruksi untuk membuat tipe generik, dan kemudian untuk menerapkan spesialisasi parametrik untuk tipe tersebut. Jadi, pada saat runtime, CLR menganggap Daftar <int> sebagai tipe yang sama sekali berbeda dari Daftar <String>.

Di bawah sampul, ia menggunakan MSIL yang sama untuk semua spesialisasi tipe referensi (jadi Daftar <String> menggunakan implementasi yang sama dengan Daftar <Object>, dengan berbagai tipe-gips di batas-batas API), tetapi setiap tipe nilai menggunakan implementasi uniknya sendiri (Daftar <int> menghasilkan kode yang sangat berbeda dari Daftar <double>).

Di Jawa, tipe generik adalah trik kompiler murni. JVM tidak memiliki gagasan tentang kelas mana yang memiliki tipe-argumen, dan itu tidak dapat melakukan spesialisasi parametrik saat runtime.

Dari perspektif praktis, itu berarti Anda tidak bisa membebani metode Java pada tipe generik. Anda tidak dapat memiliki dua metode berbeda, dengan nama yang sama, hanya berbeda pada apakah mereka menerima Daftar <String> atau Daftar <Tanggal>. Tentu saja, karena CLR tahu tentang tipe parametrik, ia tidak memiliki masalah metode penanganan kelebihan beban pada spesialisasi tipe generik.

Pada basis sehari-hari, itulah perbedaan yang paling saya perhatikan antara CLR dan JVM.

Perbedaan penting lainnya termasuk:

  • CLR memiliki penutupan (diimplementasikan sebagai delegasi C #). JVM tidak mendukung penutupan hanya sejak Java 8.

  • CLR memiliki coroutine (diimplementasikan dengan kata kunci 'hasil' C #). JVM tidak.

  • CLR memungkinkan kode pengguna untuk mendefinisikan tipe nilai baru (struct), sedangkan JVM menyediakan koleksi tetap dari tipe nilai (byte, pendek, int, panjang, float, ganda, char, boolean) dan hanya memungkinkan pengguna untuk menentukan referensi baru- jenis (kelas).

  • CLR memberikan dukungan untuk mendeklarasikan dan memanipulasi pointer. Ini sangat menarik karena JVM dan CLR menggunakan implementasi pengumpul sampah pemadatan generasi yang ketat sebagai strategi manajemen memori mereka. Dalam keadaan biasa, GC pemadatan yang ketat memiliki waktu yang sangat sulit dengan pointer, karena ketika Anda memindahkan nilai dari satu lokasi memori ke yang lain, semua pointer (dan pointer ke pointer) menjadi tidak valid. Tetapi CLR menyediakan mekanisme "pinning" sehingga pengembang dapat mendeklarasikan blok kode di mana CLR tidak diizinkan untuk memindahkan pointer tertentu. Sangat nyaman.

  • Unit kode terbesar di JVM adalah 'paket' yang dibuktikan dengan kata kunci 'terproteksi' atau bisa dibilang sebagai JAR (yaitu Java ARchive) yang dibuktikan dengan kemampuan menentukan botol di classpath dan memperlakukannya seperti folder kode. Di CLR, kelas digabungkan menjadi 'majelis', dan CLR memberikan logika untuk penalaran dan memanipulasi majelis (yang dimuat ke "AppDomains", menyediakan kotak pasir sub-aplikasi-tingkat untuk alokasi memori dan eksekusi kode).

  • Format bytecode CLR (terdiri dari instruksi MSIL dan metadata) memiliki tipe instruksi yang lebih sedikit daripada JVM. Dalam JVM, setiap operasi unik (tambahkan dua nilai int, tambahkan dua nilai float, dll) memiliki instruksi uniknya sendiri. Dalam CLR, semua instruksi MSIL bersifat polimorfik (menambahkan dua nilai) dan kompiler JIT bertanggung jawab untuk menentukan jenis operan dan membuat kode mesin yang sesuai. Saya tidak tahu strategi mana yang lebih disukai. Keduanya memiliki trade-off. Kompiler JIT HotSpot, untuk JVM, dapat menggunakan mekanisme pembuatan kode yang lebih sederhana (tidak perlu menentukan tipe operan, karena mereka sudah dikodekan dalam instruksi), tetapi itu berarti membutuhkan format bytecode yang lebih kompleks, dengan lebih banyak jenis instruksi.

Saya telah menggunakan Java (dan mengagumi JVM) selama sekitar sepuluh tahun sekarang.

Tapi, menurut saya, CLR sekarang merupakan implementasi yang unggul, dalam hampir setiap cara.

benjismith
sumber
73
Penutupan dan generator diimplementasikan pada tingkat bahasa dan hanya diwakili sebagai kelas pada tingkat CLR.
Curt Hagenlocher
2
Bagaimana dengan perbedaan cara mereka menangani heap? CLR lebih tergantung pada OS / host proc sementara JVM mengelola memori tumpukan lebih atau kurang sepenuhnya.
Kelly S. French
6
Perbedaan penting adalah kontras antara kompilasi just-in-time (CLR) dan optimisasi adaptif dalam (Oracle / Sun) JVM.
Edwin Dalorzo
1
Slot variabel lokal Java berfungsi seperti register. Tapi itu semua masih bisa diperdebatkan karena JIT mengubah slot lokal dan tumpukan menjadi register nyata.
Antimony
1
@kuhajeyan itu karena ketika CLR diperkenalkan, JVM berusia 10 tahun. itu sudah lama di IT. Ketika JVM datang pada tahun 1993 tidak ada pesaing yang serius, karena CLR (2003) ada JVM yang matang dan solid dengan pijakan yang kuat dalam industri.
Simple Fellow
25

Pertanyaan pertama Anda adalah membandingkan JVM dengan .NET Framework - Saya menganggap Anda sebenarnya bermaksud membandingkan dengan CLR. Jika demikian, saya pikir Anda bisa menulis buku kecil tentang ini ( EDIT: sepertinya Benji sudah punya :-)

Satu perbedaan penting adalah bahwa CLR dirancang untuk menjadi arsitektur bahasa-netral, tidak seperti JVM.

Perbedaan penting lainnya adalah bahwa CLR dirancang khusus untuk memungkinkan interoperabilitas tingkat tinggi dengan kode asli. Ini berarti bahwa CLR harus mengelola keandalan dan keamanan ketika memori asli diakses dan dimodifikasi, dan juga mengelola marshalling antara struktur data berbasis CLR dan struktur data asli.

Untuk menjawab pertanyaan kedua Anda, istilah "mesin virtual" adalah istilah yang lebih lama dari dunia perangkat keras (mis. Virtualisasi IBM 360 pada tahun 1960-an) yang dulu berarti emulasi perangkat lunak / perangkat keras dari mesin yang mendasarinya untuk mencapai jenis yang sama. hal-hal yang dilakukan VMWare.

CLR sering disebut sebagai "mesin eksekusi". Dalam konteks ini, itulah implementasi Mesin IL di atas x86. Ini juga yang dilakukan JVM, meskipun Anda bisa berargumen bahwa ada perbedaan penting antara bytecode polimorfik CLR dan bytecode yang diketik oleh JVM.

Jadi jawaban yang bagus untuk pertanyaan kedua Anda adalah "tidak". Tapi itu benar-benar sampai pada bagaimana Anda mendefinisikan kedua istilah ini.

EDIT: Satu lagi perbedaan antara JVM dan CLR adalah bahwa JVM (versi 6) sangat enggan untuk melepaskan memori yang dialokasikan kembali ke sistem operasi, bahkan di mana pun bisa.

Misalnya, katakanlah proses JVM dimulai dan mengalokasikan 25 MB memori dari sistem operasi pada awalnya. Kode aplikasi kemudian mencoba alokasi yang membutuhkan tambahan 50 MB. JVM akan mengalokasikan tambahan 50 MB dari sistem operasi. Setelah kode aplikasi berhenti menggunakan memori itu, itu dikumpulkan sampah dan ukuran tumpukan JVM akan berkurang. Namun, JVM hanya akan membebaskan memori sistem operasi yang dialokasikan dalam keadaan tertentu yang sangat spesifik . Kalau tidak, untuk sisa proses seumur hidup memori itu akan tetap dialokasikan.

CLR, di sisi lain, melepaskan memori yang dialokasikan kembali ke sistem operasi jika tidak lagi diperlukan. Pada contoh di atas, CLR akan merilis memori setelah tumpukan berkurang.

HTTP 410
sumber
2
Ini mutlak tidak benar bahwa JVM tidak akan membebaskan memori yang dialokasikan. Lihat jawaban saya untuk pertanyaan ini sebagai bukti: stackoverflow.com/questions/366658/…
Michael Borgwardt
Saya telah melihat JVM mengembalikan memori kembali ke Windows.
Steve Kuo
Saya telah mengubah jawaban saya untuk mengatakan bahwa JVM 6 sangat enggan untuk melepaskan memori, dengan tautan ke jawaban Ran dan Michael. Saya tidak pernah melihat perilaku ini dengan JVM 5, jadi mungkin versi itu bahkan lebih enggan.
HTTP 410
Bisakah Anda membahas bagaimana JVM secara aktif mengelola heap sementara CLR bergantung pada proses induk? Contoh spesifik yang saya gunakan adalah JVM memiliki runtime args untuk ukuran heap maks sementara lingkungan CLR default tidak. Meskipun benar aplikasi CLR yang di-host di bawah IIS dapat mengkonfigurasi IIS untuk membatasi memori, itu berarti memasukkan IIS dalam definisi mesin virtual.
Kelly S. French
@Steve Kuo, ya saya sudah melihatnya juga. biasanya antara jam 5 sore sampai 6 sore.
Simple Fellow
11

CLR dan JVM keduanya mesin virtual.

.NET Framework dan Java Runtime Environment adalah bundling dari masing-masing VM dan pustaka mereka. Tanpa perpustakaan, VM sangat tidak berguna.

Allain Lalonde
sumber
11

Lebih spesifik tentang perbedaan dapat ditemukan di dari berbagai sumber akademik dan swasta. Salah satu contoh yang baik adalah Pilihan Desain CLR .

Beberapa contoh spesifik termasuk:

  • Beberapa opperand tingkat rendah diketik seperti "tambah dua int" di mana CLR menggunakan operan polimorfik. (Yaitu fadd / iadd / ladd vs tambahkan saja)
  • Saat ini, JVM melakukan profil dan optimisasi runtime yang lebih agresif (yaitu Hotspot). CLR saat ini melakukan optimasi JIT, tetapi bukan optimasi runtime (mis. Ganti kode saat Anda sedang menjalankan).
  • CLR tidak sebaris metode virtual, JVM tidak ...
  • Dukungan untuk tipe nilai dalam CLR lebih dari sekadar "primitif".
James Schek
sumber
-11

Ini bukan mesin virtual, .net framework mengkompilasi rakitan ke dalam binary asli pada saat dijalankan pertama kali:

Dalam komputasi, kompilasi just-in-time (JIT), juga dikenal sebagai terjemahan dinamis, adalah teknik untuk meningkatkan kinerja runtime dari program komputer. JIT dibangun berdasarkan dua ide sebelumnya dalam lingkungan run-time: kompilasi bytecode dan kompilasi dinamis. Ini mengkonversi kode pada saat runtime sebelum menjalankannya secara asli, misalnya bytecode menjadi kode mesin asli. Peningkatan kinerja atas interpreter berasal dari caching hasil menerjemahkan blok kode, dan tidak hanya mengevaluasi kembali setiap baris atau operan setiap kali bertemu (lihat Bahasa yang ditafsirkan). Ia juga memiliki kelebihan dibandingkan dengan mengkompilasi kode secara statis pada waktu pengembangan, karena dapat mengkompilasi ulang kode jika ini dianggap menguntungkan, dan mungkin dapat menegakkan jaminan keamanan.

Beberapa lingkungan runtime modern, seperti Microsoft .NET Framework, sebagian besar implementasi Java, dan yang terbaru Actionscript 3, bergantung pada kompilasi JIT untuk eksekusi kode berkecepatan tinggi.

Sumber: http://en.wikipedia.org/wiki/Just-in-time_compilation

Menambahkan .NET framework berisi mesin virtual, seperti halnya Java.

Diones
sumber
10
Hanya karena mesin virtual menggunakan JIT untuk optimalisasi kinerja tidak berarti itu bukan mesin virtual lagi. Ketika programmer mengkompilasi dia mengkompilasi ke mesin virtual, meninggalkan hingga implementasi untuk melakukan eksekusi namun itu cocok
Allain Lalonde