Академический Документы
Профессиональный Документы
Культура Документы
11/01/15 10:47 AM
Page 1 of 15
11/01/15 10:47 AM
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 2 of 15
11/01/15 10:47 AM
Observando este tipo de situao, criadores de linguagens modernas como o Java resolveram embarcar na
linguagem (no caso do Java na JVM) estratgias para coleta automtica de espaos de memria que no
so mais referenciados pela aplicao, ou simplesmente, a coleta de lixo.
Usando tcnicas avanadas a JVM consegue identificar objetos no utilizados pela aplicao e
simplesmente libera o espao de maneira automtica. O exemplo da Listagem 3 mostra um espao de
memria atribudo varivel list que coletado automaticamente depois da execuo do mtodo.
Listagem 3. Exemplo de objeto que ser coletado automaticamente pela JVM.
int someSmartFunction() {
List<Integer> list = new ArrayList<>(1000);
// Faz algo com o objeto list
return 1;
}
Repare que o cdigo em Java equivalente implementao problemtica em C, apresentada da
Listagem 2, inclusive pelo fato de no executarmos nenhum mtodo para liberao de memria. Porm,
no Java, a JVM ir liberar automaticamente o espao alocado para o objeto list algum tempo depois do
mtodo ser executado.
Este trabalho realizado pelos coletores de lixo, que nada mais so do que um cdigo embarcado na JVM
que inspeciona a memria procurando por objetos que no so mais referenciados e assim efetuar a
liberao (coleta) da memria.
Isso no significa que no podemos ter vazamentos de memria em Java, pois existem cenrios em que
objetos podem se perpetuar na memria de maneira acidental, normalmente por causa de uma falha do
programador. Veremos estes cenrios mais frente e abordaremos como evit-los.
Coletores geracionais
A coleta de lixo automtica basicamente percorre os objetos existentes na memria marcando aqueles que
de alguma maneira esto sendo utilizados ou referenciados. Os que no so marcados so
automaticamente descartados, e seu espao de memria liberado para novas alocaes.
Este processo repetido quantas vezes for necessrio durante o ciclo de vida da aplicao. A cada
execuo, ou melhor, a cada ciclo de coleta de lixo, as threads da aplicao so suspensas. Sendo assim,
quanto maior o tempo da coleta de lixo, maior o impacto na performance da aplicao.
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 3 of 15
11/01/15 10:47 AM
Para tentar reduzir este impacto, os desenvolvedores da JVM se apoiaram em estudos que apontam que a
grande maioria dos objetos tem um tempo de vida muito curto, ou seja, bastam poucos ciclos de coleta
de lixo para que sejam descartados.
Poucos objetos possuem uma vida mais longa. Outra constatao que existem poucos casos de objetos
velhos referenciarem objetos jovens. Tais observaes constituem a chamada hiptese geracional, e a
base para a construo dos coletores de lixos geracionais.
Com base na hiptese geracional, sabemos que boa parte da memria deve conter objetos que logo sero
descartados e uma parte menor deve conter objetos que existem hmais tempo, os objetos velhos.
Com estas informaes em mos, os engenheiros responsveis por projetar coletores de lixo perceberam
que agrupando estes dois tipos de objetos em espaos de memria separados poderiam fazer com que o
coletor visitasse menos vezes o espao dos objetos que vivem mais, reduzindo assim o tempo de coleta
de lixo e, em consequncia, diminuindo o impacto da coleta no desempenho da aplicao.
Os coletores de lixo implementados na Java Virtual Machine normalmente so chamados de coletores
geracionais, pois eles dividem a memria disponvel para a heap da JVM (limitadas pelas flags -Xmx e Xms) em blocos chamados geraes. Os blocos principais so o bloco da gerao dos objetos jovens
(young generation) e o bloco da gerao dos objetos velhos (old generation). Alm destas ainda existe a
permanent generation (ou PermGem, recentemente extinta e substituda pela MetaSpace), que
responsvel por armazenar contedo especfico como blocos de instrues dos mtodos das classes.
Quase todos os objetos alocados so inicialmente criados na young generation (existem algumas excees
que veremos adiante). Aps vrias alocaes possvel que o espao de memria destinado a esta regio
se esgote, e caso isso ocorra a coleta de lixo realizada exclusivamente nela. Objetos que j no so mais
referenciados ou, melhor, utilizados pela aplicao, so coletados nesta etapa, que frequentemente
chamada de minor collection ou coleta secundria.
Os objetos que sobrevivem um determinado nmero de coletas secundrias so copiados para a old
generation, para que a coleta secundria, que ocorre com mais frequncia, no tenha mais que se
preocupar com eles. A este processo de mover um objeto da young generation para a old generation
damos o nome de promoo. A Figura 1 mostra a diviso geracional da memria na heap da JVM e
ilustra o processo de promoo.
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 4 of 15
11/01/15 10:47 AM
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 5 of 15
11/01/15 10:47 AM
Caso a sua aplicao crie muitos objetos de vida curta, mais do que o valor padro que a young pode
suportar normalmente, estes valores podem ser ajustados atravs da flag -XX:NewRatio=<y>. Por
exemplo, o valor -XX:NewRatio=1 diz que a young deve ser do mesmo tamanho da old generation.
Alm disso, possvel ajustar o tamanho da young generation de maneira absoluta, usando a flag XX:NewSize=<y>. Por exemplo, informando XX:NewSize=800m em uma JVM com 1 Giga, voc
est reservando 800 Mb para a Young e apenas 200 Mb para a Old Generation.
O ajuste de tamanho entre a Young e a Old generation so fundamentais para um desempenho melhor do
coletor de lixo. Uma das sugestes da Oracle deixar a JVM ajustar sozinha esta proporo, mas para isso
voc no pode definir a heap inicial (-Xms) igual heap mxima (-Xmx).
Desta forma, a JVM aprende a melhorar o valor da proporo cada vez que solicita mais memria ao
sistema operacional, at atingir o mximo (-Xmx). Esta abordagem, no entanto, possui um problema, pois
em aplicaes que rodam em containers mais pesados, como os servidores de aplicao, durante o boot do
container a JVM pode atingir seu mximo de heap, e com isso o tuning que a JVM fez pode ser especfico
para situaes de boot, no considerando o uso normal da aplicao, exigindo assim alguns ciclos de Full
GC para se reajustar.
Ajustes na promoo
Outro fator que pode ser ajustado o momento da promoo do objeto da young para a old generation.
Por padro, um objeto promovido apenas se sobreviver a 15 ciclos de coletas secundrias. Na prxima
coleta, se o objeto ainda estiver vivo, ele ser promovido para a Old generation.
Este nmero, contudo, pode ser ajustado dependendo da aplicao. Voc pode obter resultados melhores
ajustando tanto para cima como para baixo. Para isto, usamos a flag -XX:MaxTenuringThreshold=
<n>.
Conforme informado anteriormente, a maioria dos objetos alocada na Young Generation, porm existem
excees. Isso ocorre porque alguns objetos so alocados diretamente na Old Generation por consumir
muita memria (objetos grandes).
A JVM preventivamente aloca este tipo de objeto diretamente na Old Generation para evitar o
esgotamento precoce da Young Generation. Este evento chamado de promoo prematura e se ocorrer
em grande quantidade pode comprometer o bom funcionamento do GC, ocasionando grandes ciclos de
Full GC.
Para configurar o tamanho de objetos que devem ser alocados diretamente na Old Generation podemos
usar a flag -XX:PretenureSizeThreshold=<n>, onde n o tamanho em bytes.
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 6 of 15
11/01/15 10:47 AM
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 7 of 15
11/01/15 10:47 AM
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 8 of 15
11/01/15 10:47 AM
Para monitorar a coleta de lixo na JVM temos disponveis diversas ferramentas no mercado. Algumas
delas so distribudas juntamente com o JDK, como o caso do JConsole, JVisualVM e mais
recentemente o JMC (Java Mission Control), localizados na pasta bin do JDK. Estas ferramentas
possuem interface grfica e so razoavelmente simples de operar. Alm destas, h outra alternativa,
denominada jStat, tambm distribuda no JDK. O jStat uma ferramenta de console e por isso
extremamente fcil de utilizar.
O jStat se conecta a uma JVM em execuo e captura diversas informaes relativas memria, exibindo
o resultado no console. Ele possui diversas opes de execuo, dentre elas a gcutil. Para completar a
execuo desse comando, devemos informar o nmero do processo (PID) que queremos monitorar, de
quanto em quanto tempo queremos capturar os dados (em milissegundos) e por quantas vezes. Sendo
assim, o comando:
$ jstat gcutil 4433 1000 5
Ir instrumentar o processo 4433 por cinco vezes com um intervalo de um segundo entre elas. O resultado
semelhante ao contedo exposto na Listagem 4.
Listagem 4. Resultado da execuo do comando jstat gcutil 4433 1000 5.
S0
S1
YGC
YGCT
FGC
FGCT
GCT
0.00
99.96
33.32
17.24
99.16
15
0.087
0.240
0.327
0.00
99.96
33.32
17.24
99.16
15
0.087
0.240
0.327
0.00
99.96
33.32
17.24
99.16
15
0.087
0.240
0.327
0.00
99.96
33.32
17.24
99.16
15
0.087
0.240
0.327
0.00
99.96
33.32
17.24
99.16
15
0.087
0.240
0.327
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 9 of 15
11/01/15 10:47 AM
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 10 of 15
11/01/15 10:47 AM
trem parte novamente e no tarda muito para o cho ficar sujo mais uma vez. Desta vez o trem para em
uma plataforma, as portas se abrem e uma nova equipe de quatro coletores entram, porm desta vez as
portas se fecham e o trem parte.
Enquanto o trem est em movimento os faxineiros realizam os seus trabalhos. Quando eles concluem a
limpeza, o trem para novamente em outra plataforma, as portas se abrem, os faxineiros saem e o trem
retoma a viagem.
Voltando ao mundo virtual, se considerarmos que o trem representa as threads da nossa aplicao, o lixo
jogado no cho representa os objetos alocados e no mais utilizados e os faxineiros como as threads do
coletor de lixo, os trs cenrios descrevem, de maneira simplista, os trs principais tipos de coletores de
lixo da JVM:
1. SerialGC: onde apenas um faxineiro ou apenas uma thread coleta o lixo;
2. ParallelGC: onde vrios faxineiros ou vrias threads coletam o lixo;
3. Concurrent Mark Sweep: onde vrios faxineiros ou vrias threads coletam o lixo enquanto a thread
da aplicao segue em execuo.
Deixando este cenrio abstrato de lado, a seguir veremos uma explicao um pouco mais detalhada de
cada tipo de coletor de lixo aqui exposto.
O coletor serial
Como o prprio nome indica, o Serial GC, ou coletor em srie (ativado pela flag XX+UseSerialGC) tem
esse nome porque utiliza apenas uma thread para coleta de lixo. Quando este coletor acionado todas as
threads da aplicao so suspensas. importante ressaltar que quando executado na old generation (em
um Full GC), este coletor realiza uma fase adicional de compactao dos objetos sobreviventes, para evitar
a fragmentao do espao e otimizar as alocaes (ver BOX 2).
um dos coletores mais antigos na JVM e foi desenvolvido em um momento em que mquinas multicore
ainda no eram to comuns. Por usar apenas uma thread, o coletor mais simples e ainda recomendvel
para aplicaes com pouca memria ou que rodem em mquinas com um ou dois processadores.
Com o crescimento das plataformas como servio (PaaS), que normalmente disponibilizam containers
com recursos limitados, este coletor voltou a ser utilizado com frequncia pois se adequa bem a este tipo
de ambiente.
BOX 2. Fragmentao e Compactao
Normalmente a alocao de objetos na memria da JVM acontece de maneira sequencial, ou seja, um
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 11 of 15
11/01/15 10:47 AM
objeto alocado ao lado do outro, sem espaos entre eles. Porm, com o passar do tempo alguns objetos
so coletados e outros no, gerando assim espaos vazios entre objetos sobreviventes.
Com a memria fragmentada, as novas alocaes se tornam mais lentas, pois a JVM tem que percorrer os
espaos livres em busca de uma lacuna com o tamanho suficiente para o novo objeto. Por isso,
ocasionalmente a JVM realiza um processo de compactao da memria, no qual todos os objetos so
compactados e o espao livre novamente se torna contguo. A Figura 3 demostra esse processo.
Page 12 of 15
11/01/15 10:47 AM
pausas menores, como aplicaes real-time, devem optar por este coletor.
Em contrapartida, este coletor, por ser mais complexo, utiliza mais ciclos de CPU e consequentemente
reduz o desempenho geral da aplicao. Outro problema dessa coleta que fica impossvel realizar a
compactao dos objetos sobreviventes, pois novos objetos podem ser criados durante sua execuo.
Para resolver isso, este coletor realiza um Full GC Serial quando a memria atinge um certo nvel de
fragmentao. Contudo, se este tipo de situao ocorrer com frequncia, deve-se optar por outro coletor
ou realizar algum ajuste de tamanho entre a young e a old generation.
A Figura 4 apresenta graficamente a situao das threads da aplicao e do coletor de lixo nos trs tipos
de coletores que acabamos de explicar.
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 13 of 15
11/01/15 10:47 AM
Page 14 of 15
11/01/15 10:47 AM
identificar as regies mais sujas (com mais lixo do que objetos vivos) e prioriza a coleta nestas regies,
movendo os objetos sobreviventes para outras regies, fazendo com que elas fiquem limpas, otimizando
assim as alocaes.
O nome G1 uma sigla para Garbage First (primeiro o lixo), pelo fato deste coletor privilegiar a
execuo da coleta nas regies com maior quantidade de lixo.
Tunando o G1
Para usar o G1, devemos informar a flag -XX:+UseG1GC para a JVM. As flags citadas anteriormente,
como -Xms, -Xmx, -XX:NewRatio=<n> e -XX:MaxTenuringThreshold=<n>, tambm so
vlidas para este coletor. Outras flags que podem ser utilizadas para ajustar o G1 so:
-XX:MaxGCPauseMillis=n: Permite configurar o valor mximo aceitvel, em milissegundos, para
uma pausa de GC. Outros coletores tambm possuem esta flag. A JVM vai se esforar para respeitar este
valor, se for necessrio realizando mais coletas para manter o tempo dentro do especificado, mas pode
falhar (silenciosamente) nesta tentativa;
-XX:InitiatingHeapOccupancyPercent=n: Esta flag configura o percentual de ocupao necessria
para iniciar um ciclo de coleta de lixo. Se for informado o valor 0, a JVM ir realizar ciclos de coleta em
intervalos de tempo constantes. O valor padro 45, que informa que o ciclo de coleta deve ser disparado
quando a ocupao da heap for de 45%;
-XX:G1HeapRegionSize=n: Conforme explicado anteriormente, o G1 divide a heap em regies. Esta
flag permite configurar exatamente o tamanho destas regies. Caso ela no seja configurada, a JVM ir
deduzir um valor entre 1 e 32Mb, baseado no tamanho total da heap.
Nota: O mercado ainda olha para o G1 como uma aposta para o futuro, pois a prpria Oracle j anunciou
que este coletor ainda est em fase de aprimoramento.
Cedo ou tarde nos depararemos com a necessidade de realizar algum ajuste no coletor de lixo da JVM,
principalmente quando lidarmos com problemas de performance em aplicaes Java. Felizmente com as
ferramentas de instrumentao disponveis no JDK possvel identificar que estes problemas podem ser
oriundos de uma estratgia de coleta de lixo inadequada para o conjunto aplicao-ambiente.
Neste contexto, compreendendo melhor o funcionamento dos coletores disponveis na JVM, torna-se
vivel realizar uma escolha mais assertiva do tipo de coletor a ser empregado e tambm efetuar ajustes
finos no processo de coleta para obter o mximo desempenho.
http://www.devmedia.com.br/entendendo-o-garbage-collector-na-jvm/31539
Page 15 of 15