CMSClassUnloadingEnabled JVM bayrağı gerçekte ne yapar?


183

Hayatım boyunca Java VM bayrağının CMSClassUnloadingEnabledgerçekte ne yaptığının bir tanımını bulamıyorum , "PermGen problemlerinizden kurtuluyor" gibi bazı çok yüksek seviyeli tanımlar dışında ( ki öyle değil , btw).

Sun'ın / Oracle'ın sitesine baktım ve seçenekler listesi bile aslında ne yaptığını söylemiyor.

Bayrağın ismine dayanarak, CMS Çöp Toplayıcısı'nın varsayılan olarak sınıfları kaldırmadığını ve bu bayrağın açıldığını tahmin ediyorum - ama emin olamıyorum.

Yanıtlar:


219

Güncelleme Bu cevap Java 5-7 için geçerlidir, Java 8'de şu düzeltmeler yapılmıştır : https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Kudos mt'a gider . Uulu

Java 5-7 için:

Dünyadaki standart Oracle / Sun VM görünümü: Sınıflar sonsuza dek. Yüklendikten sonra, artık kimsenin umurunda olmasa bile hafızada kalırlar. Çok fazla "kurulum" sınıfına sahip olmadığınız için bu genellikle sorun olmaz (= kurulum için bir kez ve daha sonra bir daha asla kullanılmaz). Yani 1MB alırlarsa bile kimin umurunda.

Ancak son zamanlarda, Groovy gibi, çalışma zamanında sınıfları tanımlayan dillerimiz var. Her komut dosyasını çalıştırdığınızda, bir (veya daha fazla) yeni sınıf oluşturulur ve sonsuza dek PermGen'de kalırlar. Bir sunucu çalıştırıyorsanız, bellek sızıntısı olduğu anlamına gelir.

CMSClassUnloadingEnabledGC'yi etkinleştirirseniz PermGen'i de süpürür ve artık kullanılmayan sınıfları kaldırır.

[EDIT] Ayrıca etkinleştirmeniz gerekecek UseConcMarkSweepGC( Sam Hasler sayesinde ). Bu yanıta bakın: https://stackoverflow.com/a/3720052/2541


17
Göre stackoverflow.com/a/3720052/2541 için CMSClassUnloadingEnabledherhangi bir etki yaratmasını, UseConcMarkSweepGCayrıca ayarlanması gerekir
Sam Hasler

1
Bunun UseConcatSweepGC'yi kullanma fikrini nasıl etkilediğinden emin değilim, ancak CMSClassUnloadingEnabled'da son zamanlarda düzeltilen bir hata var gibi görünüyor. Burada düzeltildiği belirtildi: bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325
Bill Rosmus

3
@Kevin: Evet, kesinlikle. Altındaki Bkz groovy.codehaus.org/Running : "Groovy dinamik sınıfları oluşturur, ancak varsayılan Java VM PermGen GC gelmez Java 6 kullanıyorsanız ya da geç eklemek -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCEtkinleştirmek için gereklidir CMSClassUnloadingEnabled."
Aaron Digulla

1
UseConcMarkSweepGC ve CMSClassUnloadingEnabled öğelerini birlikte kullanma hakkında iyi bir makale. blog.redfin.com/devblog/2012/06/…
Victor

1
artık 1.8 için geçerli değil: blogs.oracle.com/poonam/…
mt.uulu

35

Blog gönderisine göre Java JVM için -XX seçeneklerinin en eksiksiz listesi , CMS çöp toplayıcısı altında sınıf boşaltma özelliğinin etkin olup olmadığını belirler. Varsayılan değer false. Adlı başka bir seçenek var ClassUnloadingolduğu true(muhtemelen) başka çöp toplayıcıları etkileyen varsayılan olarak.

Fikir şu ki, GC daha önce yüklenmiş bir sınıfın JVM'de artık kullanılmadığını tespit ederse, sınıfların bayt kodunu ve / veya yerel kodu tutmak için kullanılan belleği geri kazanabilir.

CMSClassUnloadingEnabled öğesini ayarlamak , şu anda CMS toplayıcısını kullanıyorsanız permgen sorununuza yardımcı olabilir . Ancak, CMS kullanmamanız ya da sınıf yükleyiciyle ilgili gerçek bir bellek sızıntısı olma ihtimaliniz vardır. İkinci durumda, sınıfınız asla GC'ye kullanılmamış gibi görünmeyecektir ... ve bu nedenle asla boşaltılmayacaktır.


Aaron Digulla "sınıflar sonsuza dek" diyor. Bu tamamen Java dünyasında bile kesinlikle doğru değildir. Aslında, bir sınıfın ömrü sınıf yükleyicisine bağlıdır. Dolayısıyla, bir sınıf yükleyicinin çöp toplandığını (ve bu her zaman kolay bir şey değildir) ayarlayabilirseniz, yüklediği sınıflar da çöp toplanır.

Aslında, bir web uygulamasının sıcak yeniden dağıtımını yaptığınızda olan şey budur. (Ya da en azından, kalıcı bir depolama sızıntısına yol açan sorunları önleyebiliyorsanız, olması gereken budur.)


24

Bunun yararlı olduğu bir örnek:

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledWeblogic 10.3 JVM ürünümüzü ayarlamak , JAX-WS uygulamasının her web hizmeti çağrısı için yeni bir proxy sınıfı oluşturması ve sonunda bellek yetersizliğine yol açması sorununu çözmeye yardımcı oldu.

İzlemek önemsiz değildi. Aşağıdaki kod her zaman için aynı proxy sınıfını döndürdüport

final MyPortType port = 
Service.create(
        getClass().getResource("/path/to.wsdl"), 
        new QName("http://www.example.com", "MyService"))
    .getPort(
        new QName("http://www.example.com", "MyPortType"), 
        MyPortType.class);

Dahili olarak, bu vekil , her çağrıda artırılan weblogic.wsee.jaxws.spi.ClientInstanceyeni bir $Proxy[nnnn]sınıfa yeniden temsil edilen bir örneğine devredildi n. Bayrakları eklerken n, hala artırıldı, ancak en azından bu geçici sınıflar bellekten kaldırıldı.

Daha genel bir not olarak, Java yansıması ve proxy'leri yoğun bir şekilde kullanırken bu çok yararlı olabilir. java.lang.reflect.Proxy


Gerçek deneyimi paylaşmak için +1. Ayrıca sunucunun JRuby derleme işlemleri nedeniyle çok sayıda sınıf oluşturduğu torquebox'ta da bu sorunu yaşadık.
nurettin

7
Ayrıca unutmayın-XX:+CMSPermGenSweepingEnabled-XX:+CMSClassUnloadingEnabled
nurettin

3
Bu sorun için gerçek bir düzeltme, bağlantı noktasını bir kez oluşturmak ve yeniden kullanmaktır. JAX-WS'nin bu şekilde kullanılması gerekiyordu. Bağlantı noktası ayrıca% 100 iplik korumalıdır.
rustyx

@rustyx: Bu iddiayı yetkili bir bağlantıyla destekleyebilir misiniz? Web hizmetleri proxy'lerini ve saplamalarını yeniden kullanmaktan her zaman çok dikkatli oldum ... Örneğin Apache CXF sorumluluk reddi beyanlarına bakın . Veya bu soru
Lukas Eder

1
@rukavitsya: Cevabımda söylediğim gibi. Yukarıdaki mantığı her aradığımda yeni bir vekil yaratıldı
Lukas Eder
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.