O que o sinalizador JVM CMSClassUnloadingEnabled realmente faz?

183

CMSClassUnloadingEnabledDurante toda a minha vida, não consigo encontrar uma definição do que o sinalizador Java VM realmente faz, além de algumas definições muito difusas de alto nível, como "elimina os problemas do PermGen" (o que não acontece , aliás).

Eu procurei no site da Sun / Oracle e mesmo a lista de opções não diz exatamente o que faz.

Com base no nome do sinalizador, suponho que o CMS Garbage Collector por padrão não descarregue classes, e esse sinalizador o ativa - mas não tenho certeza.

Rico
fonte

Respostas:

219

Atualização Esta resposta é relevante para Java 5-7, o Java 8 corrigiu isso: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Os kudos vão para mt. uulu

Para Java 5-7:

A aparência padrão do Oracle / Sun VM no mundo é: As aulas são para sempre. Assim, uma vez carregados, eles permanecem na memória, mesmo que ninguém se importe mais. Isso geralmente não é um problema, pois você não possui muitas classes puramente de "configuração" (= usadas uma vez para a instalação e nunca mais). Portanto, mesmo que ocupem 1 MB, quem se importa.

Ultimamente, porém, temos linguagens como Groovy, que definem classes em tempo de execução. Toda vez que você executa um script, uma (ou mais) novas classes são criadas e permanecem no PermGen para sempre. Se você estiver executando um servidor, isso significa que você tem um vazamento de memória.

Se você ativar CMSClassUnloadingEnabledo GC, também varrerá o PermGen e removerá as classes que não são mais usadas.

[EDIT] Você também terá que ativar UseConcMarkSweepGC(graças a Sam Hasler ). Veja esta resposta: https://stackoverflow.com/a/3720052/2541

Aaron Digulla
fonte
17
De acordo com stackoverflow.com/a/3720052/2541 para CMSClassUnloadingEnabledter qualquer impacto, UseConcMarkSweepGCtambém deve ser definido
Sam Hasler
1
Não tenho certeza de como isso afeta a idéia de usar o UseConcatSweepGC, mas parece que houve um bug recentemente corrigido no CMSClassUnloadingEnabled. É observado como corrigido aqui: bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325
Bill Rosmus,
3
@ Kevin: Sim, definitivamente. Veja na parte inferior do groovy.codehaus.org/Running : "O Groovy cria classes dinamicamente, mas a Java VM padrão não aplica o PermGen ao GC. Se você estiver usando o Java 6 ou posterior, é necessário adicionar -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCPara ativar CMSClassUnloadingEnabled."
Aaron Digulla
1
Um bom artigo sobre como usar UseConcMarkSweepGC e CMSClassUnloadingEnabled juntos. blog.redfin.com/devblog/2012/06/…
Victor
1
não é mais válido para 1.8: blogs.oracle.com/poonam/…
mt.uulu 23/17
35

De acordo com a postagem do blog A lista mais completa de opções -XX para Java JVM , determina se o descarregamento de classe está ativado no coletor de lixo do CMS. O padrão é false. Há outra opção chamada ClassUnloadingque é truepor padrão que (presumivelmente) afeta os outros coletores de lixo.

A idéia é que, se o GC detectar que uma classe carregada anteriormente não é mais usada em nenhum lugar da JVM, poderá recuperar a memória usada para manter as classes pelo bytecode e / ou código nativo.

Definir CMSClassUnloadingEnabled pode ajudar com seu problema de permgen se você estiver usando o coletor CMS no momento . Mas as chances são de que você não esteja usando o CMS ou que tenha um vazamento de memória genuíno relacionado ao carregador de classes. Neste último caso, sua classe nunca parecerá estar sendo usada pelo GC ... e, portanto, nunca será descarregada.


Aaron Digulla diz que "as aulas são para sempre". Isso não é estritamente verdade, mesmo no mundo puramente Java. De fato, a vida útil de uma classe está ligada ao seu carregador de classes. Portanto, se você puder organizar que um carregador de classes seja coletado como lixo (e isso nem sempre é fácil), as classes que ele carregou também serão coletadas.

De fato, é isso que acontece quando você faz uma reimplementação a quente de um aplicativo da web. (Ou pelo menos, é isso que deve acontecer, se você puder evitar os problemas que levam a um vazamento de armazenamento permanente).

Stephen C
fonte
24

Um exemplo em que isso é útil:

A configuração -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledem nossa Weblogic 10.3 JVM ajudou a resolver um problema em que a implementação do JAX-WS criou uma nova classe de proxy para cada chamada de serviço da web, levando a erros de falta de memória.

Não foi trivial rastrear. O código a seguir sempre retornava a mesma classe de proxy paraport

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);

Internamente, esse proxy delegou para uma instância de weblogic.wsee.jaxws.spi.ClientInstance, que novamente delegou para uma nova $Proxy[nnnn]classe onde nfoi incrementada a cada chamada. Ao adicionar os sinalizadores,n ainda era incrementado, mas pelo menos essas classes temporárias foram removidas da memória.

Em uma observação mais geral, isso pode ser muito útil ao fazer uso pesado de reflexão e proxies Java através de java.lang.reflect.Proxy

Lukas Eder
fonte
+1 para compartilhar experiências reais. Também tivemos esse problema no torquebox, em que o servidor gerou um grande número de classes devido aos processos de compilação do JRuby.
precisa
7
observe também que -XX:+CMSPermGenSweepingEnabledestá obsoleto em favor de-XX:+CMSClassUnloadingEnabled
nurettin 22/03/2013
3
Uma correção real para esse problema é criar a porta uma vez e reutilizá-la. É assim que o JAX-WS deve ser usado. A porta também é 100% segura para threads.
21139 rustyx
@rustyx: Você pode apoiar essa afirmação com algum link oficial? Eu sempre fui muito cauteloso ao reutilizar proxies e stubs de serviços da Web ... Por exemplo, veja isenções de responsabilidade do Apache CXF . Ou esta pergunta
Lukas Eder
1
@rukavitsya: Como eu disse na minha resposta. Toda vez que chamei a lógica acima, um novo proxy foi criado
Lukas Eder