Apa yang sebenarnya dilakukan oleh JVM flag CMSClassUnloadingEnabled?
183
Saya tidak bisa seumur hidup saya menemukan definisi tentang apa yang CMSClassUnloadingEnabledsebenarnya dilakukan flag Java VM , selain beberapa definisi tingkat tinggi yang sangat kabur seperti "menghilangkan masalah PermGen Anda" ( yang tidak , btw).
Saya telah melihat situs Sun / Oracle, dan bahkan daftar opsi tidak benar-benar mengatakan apa fungsinya.
Berdasarkan nama bendera, saya menduga bahwa Pengumpul Sampah CMS tidak secara default membongkar kelas, dan bendera ini menyalakannya - tapi saya tidak yakin.
Tampilan standar Oracle / Sun VM di dunia adalah: Kelas selamanya. Jadi, sekali dimuat, mereka tetap dalam memori bahkan jika tidak ada yang peduli lagi. Ini biasanya bukan masalah karena Anda tidak memiliki banyak kelas "pengaturan" murni (= digunakan sekali untuk pengaturan dan kemudian tidak pernah lagi). Jadi meskipun mereka mengambil 1MB, siapa yang peduli
Namun belakangan ini, kami memiliki bahasa seperti Groovy, yang mendefinisikan kelas saat runtime. Setiap kali Anda menjalankan skrip, satu (atau lebih) kelas baru dibuat dan mereka tetap di PermGen selamanya. Jika Anda menjalankan server, itu artinya Anda mengalami kebocoran memori.
Jika Anda mengaktifkan CMSClassUnloadingEnabledGC akan menyapu PermGen juga, dan menghapus kelas yang tidak lagi digunakan.
Menurut stackoverflow.com/a/3720052/2541 untuk CMSClassUnloadingEnabledmemiliki dampak apa pun, UseConcMarkSweepGCjuga harus ditetapkan
Sam Hasler
1
Tidak yakin bagaimana ini memengaruhi gagasan untuk menggunakan UseCompatSweepGC, tetapi tampaknya ada bug yang baru-baru ini diperbaiki di CMSClassUnloadingEnabled. Dikatakan telah diperbaiki di sini: bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325
Bill Rosmus
3
@ Kevin: Ya, tentu saja. Lihat di bagian bawah groovy.codehaus.org/Running : "Groovy membuat kelas secara dinamis, tetapi Java VM default tidak menggunakan PermGen. Jika Anda menggunakan Java 6 atau lebih baru, add -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCDiperlukan untuk mengaktifkan CMSClassUnloadingEnabled."
Menurut posting blog Daftar -XX opsi paling lengkap untuk Java JVM , menentukan apakah kelas bongkar diaktifkan di bawah pengumpul sampah CMS. Standarnya adalah false. Ada opsi lain yang disebut ClassUnloadingyaitu secara truedefault yang (mungkin) mempengaruhi pemulung lainnya.
Idenya adalah bahwa jika GC mendeteksi bahwa kelas yang dimuat sebelumnya tidak lagi digunakan di mana pun di JVM, itu dapat merebut kembali memori yang digunakan untuk menyimpan bytecode dan / atau kode asli kelas.
Mengatur CMSClassUnloadingEnabled mungkin membantu dengan masalah permgen Anda jika Anda saat ini menggunakan kolektor CMS . Tetapi kemungkinannya adalah bahwa Anda tidak menggunakan CMS, atau bahwa Anda memiliki kebocoran memori terkait classloader asli. Dalam kasus yang terakhir, kelas Anda tidak akan pernah terlihat oleh GC tidak digunakan ... dan karenanya tidak akan pernah diturunkan.
Aaron Digulla mengatakan "kelas adalah untuk selamanya". Ini tidak sepenuhnya benar, bahkan di dunia Jawa murni. Bahkan, masa hidup suatu kelas terkait dengan classloader-nya. Jadi jika Anda dapat mengatur bahwa classloader adalah sampah yang dikumpulkan (dan itu tidak selalu mudah dilakukan) kelas-kelas yang dimuatnya juga akan menjadi sampah yang dikumpulkan.
Faktanya, ini adalah apa yang terjadi ketika Anda melakukan penempatan kembali panas suatu webapp. (Atau setidaknya, itulah yang seharusnya terjadi, jika Anda dapat menghindari masalah yang menyebabkan kebocoran penyimpanan permgen.)
Pengaturan -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledpada Weblogic 10.3 JVM kami membantu menyelesaikan masalah di mana implementasi JAX-WS menciptakan kelas proxy baru untuk setiap panggilan layanan web, yang pada akhirnya menyebabkan kesalahan memori.
Itu tidak mudah untuk dilacak. Kode berikut selalu mengembalikan kelas proxy yang sama untukport
finalMyPortType port =Service.create(
getClass().getResource("/path/to.wsdl"),newQName("http://www.example.com","MyService")).getPort(newQName("http://www.example.com","MyPortType"),MyPortType.class);
Secara internal, proksi ini didelegasikan ke instance weblogic.wsee.jaxws.spi.ClientInstance, yang lagi-lagi didelegasikan ke $Proxy[nnnn]kelas baru di mana nbertambah pada setiap panggilan. Saat menambahkan flag, nmasih bertambah, tetapi setidaknya kelas sementara itu dihapus dari memori.
Pada catatan yang lebih umum, ini bisa sangat berguna ketika menggunakan refleksi Jawa dan proxy secara mendalam java.lang.reflect.Proxy
+1 untuk berbagi pengalaman nyata. Kami juga memiliki masalah ini di torquebox di mana server menghasilkan sejumlah besar kelas karena proses kompilasi JRuby.
nurettin
7
juga perhatikan bahwa -XX:+CMSPermGenSweepingEnabledsudah usang dalam mendukung-XX:+CMSClassUnloadingEnabled
nurettin
3
Perbaikan nyata untuk masalah ini adalah membuat port sekali dan menggunakannya kembali. Begitulah seharusnya JAX-WS digunakan. Port ini juga 100% aman.
rustyx
@rustyx: Bisakah Anda mendukung klaim itu dengan beberapa tautan otoritatif? Saya selalu sangat berhati-hati dalam menggunakan kembali proksi dan stub layanan web ... Misalnya, sanggahan Apache CXF . Atau pertanyaan ini
Lukas Eder
1
@rukavitsya: Seperti yang sudah saya katakan dalam jawaban saya. Setiap kali saya menyebut logika di atas, proxy baru dibuat
CMSClassUnloadingEnabled
memiliki dampak apa pun,UseConcMarkSweepGC
juga harus ditetapkan-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC
.UseConcMarkSweepGC
Diperlukan untuk mengaktifkanCMSClassUnloadingEnabled
."Menurut posting blog Daftar -XX opsi paling lengkap untuk Java JVM , menentukan apakah kelas bongkar diaktifkan di bawah pengumpul sampah CMS. Standarnya adalah
false
. Ada opsi lain yang disebutClassUnloading
yaitu secaratrue
default yang (mungkin) mempengaruhi pemulung lainnya.Idenya adalah bahwa jika GC mendeteksi bahwa kelas yang dimuat sebelumnya tidak lagi digunakan di mana pun di JVM, itu dapat merebut kembali memori yang digunakan untuk menyimpan bytecode dan / atau kode asli kelas.
Mengatur CMSClassUnloadingEnabled mungkin membantu dengan masalah permgen Anda jika Anda saat ini menggunakan kolektor CMS . Tetapi kemungkinannya adalah bahwa Anda tidak menggunakan CMS, atau bahwa Anda memiliki kebocoran memori terkait classloader asli. Dalam kasus yang terakhir, kelas Anda tidak akan pernah terlihat oleh GC tidak digunakan ... dan karenanya tidak akan pernah diturunkan.
Aaron Digulla mengatakan "kelas adalah untuk selamanya". Ini tidak sepenuhnya benar, bahkan di dunia Jawa murni. Bahkan, masa hidup suatu kelas terkait dengan classloader-nya. Jadi jika Anda dapat mengatur bahwa classloader adalah sampah yang dikumpulkan (dan itu tidak selalu mudah dilakukan) kelas-kelas yang dimuatnya juga akan menjadi sampah yang dikumpulkan.
Faktanya, ini adalah apa yang terjadi ketika Anda melakukan penempatan kembali panas suatu webapp. (Atau setidaknya, itulah yang seharusnya terjadi, jika Anda dapat menghindari masalah yang menyebabkan kebocoran penyimpanan permgen.)
sumber
Contoh di mana ini berguna:
Pengaturan
-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled
pada Weblogic 10.3 JVM kami membantu menyelesaikan masalah di mana implementasi JAX-WS menciptakan kelas proxy baru untuk setiap panggilan layanan web, yang pada akhirnya menyebabkan kesalahan memori.Itu tidak mudah untuk dilacak. Kode berikut selalu mengembalikan kelas proxy yang sama untuk
port
Secara internal, proksi ini didelegasikan ke instance
weblogic.wsee.jaxws.spi.ClientInstance
, yang lagi-lagi didelegasikan ke$Proxy[nnnn]
kelas baru di manan
bertambah pada setiap panggilan. Saat menambahkan flag,n
masih bertambah, tetapi setidaknya kelas sementara itu dihapus dari memori.Pada catatan yang lebih umum, ini bisa sangat berguna ketika menggunakan refleksi Jawa dan proxy secara mendalam
java.lang.reflect.Proxy
sumber
-XX:+CMSPermGenSweepingEnabled
sudah usang dalam mendukung-XX:+CMSClassUnloadingEnabled