Mengapa JIT cache JVM tidak mengkompilasi kode?

107

Implementasi JVM kanonik dari Sun menerapkan beberapa pengoptimalan yang cukup canggih pada bytecode untuk mendapatkan kecepatan eksekusi yang mendekati asli setelah kode dijalankan beberapa kali.

Pertanyaannya adalah, mengapa kode yang dikompilasi ini tidak di-cache ke disk untuk digunakan selama penggunaan berikutnya dari fungsi / kelas yang sama?

Seperti berdiri, setiap kali program dijalankan, kompilator JIT dijalankan lagi, daripada menggunakan versi kode yang telah dikompilasi sebelumnya. Bukankah menambahkan fitur ini menambah dorongan yang signifikan pada waktu jalan awal program, ketika bytecode pada dasarnya sedang diinterpretasikan?

Chinmay Kanchi
sumber
4
Sebuah utas membahas masalah ini: javalobby.org/forums/thread.jspa?threadID=15812
miku
2
Tapi pertanyaan yang tidak mungkin menarik jawaban pasti.
bmargulies
1
Saya tidak yakin tentang peningkatan yang "signifikan", karena dengan demikian Anda harus memuat barang-barang yang di-JIT dari disk alih-alih JITing dalam memori. Itu bisa mempercepat, tetapi atas dasar kasus per kasus.
R. Martinho Fernandes
1
Terima kasih atas jawaban yang luar biasa semuanya! Semua jawaban sama-sama valid, jadi saya pergi dengan komunitas untuk yang satu ini ...
Chinmay Kanchi
Ini adalah pertanyaan yang bagus jika Anda bertanya kepada saya :)
Alfred

Jawaban:

25

Tanpa menggunakan cut'n'paste dari tautan yang diposting @MYYN, saya curiga ini karena pengoptimalan yang dilakukan JVM tidak statis, melainkan dinamis, berdasarkan pola data serta pola kode. Sepertinya pola data ini akan berubah selama masa pakai aplikasi, membuat pengoptimalan yang disimpan dalam cache kurang dari optimal.

Jadi, Anda memerlukan mekanisme untuk menetapkan apakah pengoptimalan yang disimpan masih optimal, pada titik mana Anda sebaiknya mengoptimalkan ulang dengan cepat.

skaffman
sumber
6
... atau Anda bisa menawarkan ketekunan sebagai opsi , seperti yang dilakukan JVM Oracle - memberdayakan pemrogram tingkat lanjut untuk mengoptimalkan kinerja aplikasi mereka kapan dan di mana mereka hanya tahu bahwa polanya tidak berubah, di bawah tanggung jawab mereka. Kenapa tidak?!
Alex Martelli
2
Karena itu mungkin tidak sepadan. Jika SUN, IBM, atau BEA tidak menganggapnya bermanfaat untuk kinerja JVM mereka, akan ada alasan bagus untuk itu. Mungkin pengoptimalan RT mereka lebih cepat daripada Oracle, itulah sebabnya Oracle menyimpannya dalam cache.
Skaffman
9
Mengapa tidak menggunakan pengoptimalan tersimpan sebagai titik awal, untuk menggunakan apa yang telah dipelajari pada proses sebelumnya? Dari sana JIT dapat bekerja seperti biasa dan melakukan optimasi ulang. Saat dimatikan, kode itu dapat dipertahankan lagi dan digunakan di proses berikutnya sebagai titik awal baru.
Puce
1
@ Puce Satu-satunya alasan yang dapat saya pikirkan adalah bahwa AFAIK Anda tidak mendapatkan statistik profil dari menjalankan kode yang dioptimalkan. Jadi Anda tidak punya cara untuk meningkatkan ...
maaartinus
1
Saya pribadi akan baik-baik saja dengan opsi "pertahankan informasi profil JIT antara proses" dengan semua peringatan bahwa "ini hanya akan berlaku dengan JVM yang sama persis, data yang sama, dll. Dan sebaliknya diabaikan". Mengenai mengapa ini belum diterapkan, saya berharap bahwa kerumitan tambahan dalam mempertahankan dan memvalidasi data benih JIT terlalu banyak untuk mengambil sumber daya dari proyek lain. Mengingat pilihan antara stream ini dan Java 8 lambda +, saya lebih suka yang terakhir.
Thorbjørn Ravn Andersen
25

JVM Oracle memang didokumentasikan untuk melakukannya - mengutip Oracle,

compiler dapat memanfaatkan model resolusi kelas JVM Oracle untuk secara opsional mempertahankan metode Java yang dikompilasi di seluruh panggilan database, sesi, atau instance. Persistensi tersebut menghindari overhead kompilasi ulang yang tidak perlu di seluruh sesi atau instance, ketika diketahui bahwa kode Java secara semantik tidak berubah.

Saya tidak tahu mengapa semua implementasi VM yang canggih tidak menawarkan opsi serupa.

Alex Martelli
sumber
8
Karena JVM canggih lainnya tidak memiliki RDBMS perusahaan besar yang membunyikan klakson yang berguna untuk menyimpan barang di :)
skaffman
Wow! itu berarti Kompilasi terkadang disimpan dalam cache. Ini kabar baik!
Sandeep Jindal
J9 IBM juga didokumentasikan untuk melakukannya.
pengguna314104
9
Perhatikan bahwa Oracle JVM ini adalah yang ada di dalam Oracle Database, bukan unduhan yang didapat Oracle saat membeli Sun.
Thorbjørn Ravn Andersen
14

Pembaruan untuk jawaban yang ada - Java 8 memiliki JEP yang didedikasikan untuk menyelesaikan ini:

=> JEP 145: Kode Kompilasi Cache . Tautan baru .

Pada tingkat yang sangat tinggi, tujuan yang dinyatakan adalah :

Simpan dan gunakan kembali kode native terkompilasi dari proses sebelumnya untuk meningkatkan waktu startup aplikasi Java yang besar.

Semoga ini membantu.

Eugen
sumber
3
Fitur tersebut belum mencapai rilis final .
assylias
5

Excelsior JET memiliki kompiler JIT caching sejak versi 2.0, dirilis pada tahun 2001. Selain itu, kompiler AOT-nya dapat mengkompilasi ulang cache menjadi satu DLL / objek bersama menggunakan semua pengoptimalan.

Dmitry Leskov
sumber
3
Ya, tapi pertanyaannya adalah tentang JVM kanonik, yaitu JVM Sun. Saya sangat menyadari bahwa ada beberapa kompiler AOT untuk Java serta JVM caching lainnya.
Chinmay Kanchi
0

Saya tidak tahu alasan sebenarnya, tidak terlibat dengan cara apa pun dalam implementasi JVM, tetapi saya dapat memikirkan beberapa alasan yang masuk akal:

  • Ide Java adalah menjadi bahasa tulis-sekali-dijalankan-di mana saja, dan memasukkan hal-hal yang telah dikompilasi ke dalam file kelas adalah jenis pelanggaran itu (hanya "jenis" karena tentu saja kode byte yang sebenarnya akan tetap ada)
  • Ini akan meningkatkan ukuran file kelas karena Anda akan memiliki kode yang sama di sana beberapa kali, terutama jika Anda menjalankan program yang sama di bawah beberapa JVM yang berbeda (yang sebenarnya tidak jarang, ketika Anda menganggap versi yang berbeda sebagai JVM yang berbeda, yang Anda benar-benar harus dilakukan)
  • File kelas itu sendiri mungkin tidak dapat ditulis (meskipun akan sangat mudah untuk memeriksanya)
  • Pengoptimalan JVM sebagian didasarkan pada informasi waktu proses dan pada proses lain mungkin tidak dapat diterapkan (meskipun masih memberikan beberapa manfaat)

Tapi saya benar-benar menebak, dan seperti yang Anda lihat, saya tidak benar-benar berpikir alasan saya adalah penghenti pertunjukan yang sebenarnya. Saya pikir Sun tidak menganggap dukungan ini sebagai prioritas, dan mungkin alasan pertama saya mendekati kebenaran, karena melakukan ini biasanya mungkin juga membuat orang berpikir bahwa file kelas Java benar-benar membutuhkan versi terpisah untuk setiap VM daripada menjadi lintas platform.

Cara yang saya sukai sebenarnya adalah memiliki penerjemah bytecode-to-native terpisah yang dapat Anda gunakan untuk melakukan sesuatu seperti ini secara eksplisit sebelumnya, membuat file kelas yang secara eksplisit dibangun untuk VM tertentu, dengan kemungkinan bytecode asli di dalamnya sehingga Anda dapat berjalan dengan VM yang berbeda juga. Tapi itu mungkin berasal dari pengalaman saya: Saya kebanyakan melakukan Java ME, di mana sangat menyakitkan karena kompiler Java tidak lebih pintar tentang kompilasi.

JaakkoK
sumber
1
ada tempat di classfile untuk hal-hal seperti itu, sebenarnya itu adalah maksud asli (simpan kode JIT sebagai atribut di classfile).
TofuBeer
@TofuBeer: Terima kasih atas konfirmasinya. Saya curiga itu mungkin masalahnya (itulah yang akan saya lakukan), tetapi tidak yakin. Diedit untuk menghapus itu sebagai kemungkinan alasan.
JaakkoK
Saya pikir Anda tepat sasaran dengan poin terakhir Anda. Yang lain bisa diselesaikan, tapi bagian terakhir itu, menurut saya, adalah alasan utama kode JITed tidak bertahan.
Sasha Chedygov
1
Paragraf terakhir tentang compiler bytecode-to-native eksplisit adalah apa yang Anda miliki saat ini di .NET dengan NGEN ( msdn.microsoft.com/en-us/library/6t9t5wcf(VS.71).aspx ).
R. Martinho Fernandes