560 likes | 719 Views
Garbage Collector. Desenvolvendo aplicações de forma eficiente ! Piza*Ahagon*Sponch Os Lixeiros. Goal. Dicas de como escrever código legível que busque a melhor eficiência do Garbage Collector em termos de throughput, responsividade e etc. Agenda. Conceitos de Garbage Collection
E N D
Garbage Collector Desenvolvendo aplicações de forma eficiente ! Piza*Ahagon*Sponch Os Lixeiros
Goal Dicas de como escrever código legível que busque a melhor eficiência do Garbage Collector em termos de throughput, responsividade e etc ... Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Agenda • Conceitos de Garbage Collection • Dicas de programação • Problemas com finalização • Usando referências de objeto • Evitando Memory Leak • Conclusão Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Agenda • Conceitos de Garbage Collection • Dicas de Programação • Problemas com finalização • Usando referências de objeto • Evitando Memory Leak • Conclusão Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Fundamentos • O GC é uma thread de baixa prioridade que ... Vamos falar sério, você espera mais desta palestra Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Fundamentos • Encontrar e Coletar objetos não alcançáveis • Não Alcançável = qualquer coisa não transitivamente acessível a partir das raízes da aplicação • Automático e Seguro • O desenvolvedor não interfere ativamente na execução do GC, apenas em sua política de execução. • O GC não interfere na integridade do seu código. • Grande variedade de Atuações • Compactação/ sem compactação. • Algorítmos: Copying, mark-sweep, mark-compact ... • Alocação: Linear, listas ... Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Garbage Collection Geracional • Mantém objetos novos e antigos em espaços geracionais (geração = idade) separados. • Hipótese de Geração Fraca • A maioria dos objetos morre jovem • O GC concentra esforço nos objetos jovens • Precisa manter a rastreabiliade de ponteiros dos objetos antigos para os jovens • Mantém referencia apenas de objetos antigos que apontam para objetos jovens. • Eventualmente coleta os objetos antigos. • Algorítmos diferentes para cada espaço de geração. • Possibilidade de algorítmos mais especializados. • Para objetos jovens se preocupa com a eficiência das alocações. • Para objetos antigos se preocupa com eficiência no gerenciamento de memória. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
GC Geracional: Desenho Esquemático Geração Jovem Geração Velha Promoção de Objetos Remembered Set Card Table Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
GC Geracional Conclusões • Para utilizá-lo sua aplicação deve ser desenvolvida com a HI de geração fraca. • O espaço de objetos jovem desperdiça memória, mas utiliza uma área pequena da Heap. • O espaço de objetos antigos é melhor gerenciado, pois utiliza a maior parte da Heap. • Objetos jovens são alocados e desalocados rapidamente e frequentemente. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Mais Conclusões • Objetos antigos são alocados e desalocados mais lentamente, entretanto devido a pouca frequencia isto não gera impacto significativo na aplicação. • Existe uma barreira de escrita na geração velha: apenas uma pequena tabela de alocação e atualizada quando é criada ou deletada uma referência de um objeto antigo a um novo. Isto gera um impacto na performance de curto prazo (pois o GC precisa manter esta tabela), mas a a longo prazo diminui as operações na geração velha, melhorando o throughput da aplicação. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Garbage Collection Incremental • Minimiza pausas na aplicação devido ao trabalho do GC • GC atua ao mesmo tempo que a aplicação. • O GC considera que o grafo de objetos da aplicação é mutante. • O GC precisa ser avisado de todas as mutações no grafo. • Também utiliza uma barreira de escrita (remembered set). • Se apenas a geração velha é incremental, não é necessário manter referências aos objetos jovens. • Não utilize -XX:+UseParallelGCe -XX:+UseParNewGC com este algorítmo. • Medidas de Comparação (-XX:+PrintGCDetails ) : • [GC [DefNew: 2074K->25K(2112K), 0.0050065 secs][Train: 1676K->1633K(63424K), 0.0082112 secs] 3750K->1659K(65536K), 0.0138017 secs] Train (GC Incremental): Tamanho Antes -> Tamanho Depois, tempo da operação • [GC [DefNew: 2049K->2049K(2112K), 0.0003304 secs][Train MSC: 61809K->357K(63424K), 0.3956982 secs] 63859K->394K(65536K), 0.3987650 secs] Train MSC (Full Collection: mark-sweep-compact): Tamanho Antes -> Tamanho Depois, tempo da operação Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Como o GC Trabalha • Alocação • Super Rápida • GCs, não compactados são mais lentos. • Tamanho dos Objetos • Quanto maior mais trabalho para o GC fazer o rastreamento das referencias e dados do objeto. • Atualizações em variáveis de referência • Quanto mais referencias mais overheads, especialmente os incrementais e geracionais. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Agenda • Conceitos de Garbage Collection • Dicas de Programação • Problemas com finalização • Usando referências de objeto • Evitando Memory Leak • Conclusão Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Dicas de programação • Alocação de Objetos • Tamanho de Objetos • Ponteiros Nulos • Chamadas Explícitas ao GC • Dimensionamento das Estruturas de Dados • Pool de Objetos Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Alocação de Objetos • Alocação de Objetos é Muito Rápido ! • 10 instruções nativas de máquina (casos comuns) • Não há barreira de escrita • Não é mais lento que C/C++ • Coleta de Objetos Jovens é muito rápida em GCs Geracionais • Conclusão: • Não tenha medo de alocar pequenos objetos para resultados intermediários. • GC adora objetos pequenos e imutáveis. • GCs Geracionais adoram pequenos objetos de curta duração. • Isso não significa que criar objetos desnecessariamente é saudável. • Bom senso: Quanto mais alocações, mais o GC vai trabalhar. • Criar objetos imutáveis para situações específicas é melhor do que repassá-lo continuamente como variável a várias chamadas de métodos. • Use código claro e simples com mais alocações ao invés de código obscuro com muitas trocas de mensagens entre objetos. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
“Grandes” Objetos • Problemas com utilização de “Grandes” Objetos • Alocação cara (por caminhos não “tunados”). • Inicialização de variáveis cara (“Zeroing”). • Podem causar quedas de performance e throughput (veja abaixo). • “Grandes” objetos de vários tamanhos podem causar fragmentação em GCs não compactados. • Devem ser evitados sempre que necessário. • Problema: • O que é um objeto grande ? Faça o menor que puder sem ferir seu modelo de negócios e boas práticas. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Ponteiros Nulos //Terminou a utilização do objeto dont-do-this = null; //Quando terminar de //utilizar a variável • Não é necessário, confie no GC (JIT) • No melhor caso: trabalho desnecessário. • No pior caso: introduz bugs. • Casos Excepcionais • Implementações de ArrayList, ou outras estruturas de dados que o forçam a gerenciar manualmente a memória utilizada. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Chamadas Explícitas ao GC • System.gc(); • Tanto trabalho para “tunar” o GC e esta ação provoca um “stop-the-world full GC”. • Utilize -XX:+DisableExplicitGC • Findbugs pode encontrar as chamadas explícitas. • Único caso permitido em algorítmos de GC distribuído entre chamadas RMI – Acho que não é a sua necessidade ;-) Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Dimensionamento das Estruturas de Dados • Evite re-dimensionamentos desnecessários • Cópia de Arrays, por exemplo, é uma operação crítica para performance. • Pode causar fragmentação do GC. • Aloca o Array duas vezes ArrayList<String> list = new ArrayList<String>(); list.ensureCapacity(1024); • Forma sugerida, seja realista. ArrayList<String> list = new ArrayList<String>(1024); Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Pool de Objetos • É muito ruim ! • Lembremo-nos dos conceitos de GCs Geracionais • Objetos não utilizados no pool são como impostos sem benefícios para o GC. • Mesmo quando não utilizados o GC deve processá-los. • A aplicação não está utilizando, onde está a vantagem ? • Exceções • Pool de Threads • Pool de Conexões • Alguém poderia nomear algum outro ? • Motivo • Estes pools são extremamente caros de serem inicializados • Neste caso, utilize bibliotecas já testadas e padronizadas. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Agenda • Conceitos de Garbage Collection • Dicas de programação • Problemas com finalização • Usando referências de objeto • Evitando Memory Leak • Conclusão Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Finalize [JLS 12.6] • Libera recursos que não são coletados automaticamente pelo GC • Último método executado antes da morte do Objeto. • A especificação não garante em que momento o método será chamado. • Não especifica qual Thread chamará o método finalizador • Não garante ordem Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
O que acontece na prática • Implementação do método não trivial e é muito suscetível a erros • Durante a alocação a JVM trata objetos que sobrescrevem o método finalize de forma diferente. • Degrada performance da coleta do objeto pelo GC • São gastos dois ciclos do GC (melhor caso). • Primeiro ciclo identifica os objetos que não são alcançáveis e os coloca em uma fila para a execução do finalizador. • Segundo ciclo é usado para liberar a memória do heap. • SSSe o método finalize já foi executado Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
O que mais acontece na prática • Objetos que implementam finalize ficam mais tempo em memória. • Mais pressão sobre o GC. • Aplicação pode terminar e não executar todos os objetos que estão na fila de finalização – Trabalho arriscado e desnecessário . Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Quando usar Finalização? • Necessidade de liberar recursos que são nativos. • Quando o objeto faz chamadas nativas e aloca memória (uma função em C que deve fazer uma chamada malloc) • Tentar garantir que um recurso foi realmente liberado. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Como usar Finalização? • Regra de ouro Não use ! Mas se precisar saiba que ... • Finalize no Java != Destructor em C++ • Escreva o método finalize usando boas práticas • (Effective Java http://www.amazon.com/Effective-Java-Programming-Language-Guide/dp/0321356683) • Chame o método runFinalizerOnExit das classes RunTime ou System • Objetos que implementam finalize devem conter o menor numero possível de referencias. • Finalização é o quase o mesmo que “chorar pelo leite derramado”, utilize como último suspiro. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Como usar Finalização? class MyObject { private byte[] buffer1; private byte[] buffer2; private native void nativeDispose(); public void dispose() { nativeDispose(); } protected void finalize() throws Throwable{ try { dispose(); } finally { super.finalize(); } } } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Como usar Finalização? class MyObject2 extends MyObject { private byte[] buffer3 = new byte[16 * 1024 * 1024]; } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Como usar Finalização? class MyObject3 { private MyObject obj; private byte[] buffer3 = new byte[16 * 1024 * 1024]; public void dispose() { obj.dispose(); } } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Por Último ... finally { • Utilizar a finalização pode comprometer outros recursos que causam problemas de difícil diagnóstico. • e.g. Sincronização • Antes de utilizar leia: • Bloch Joshua, Effective Java(TM) Programming Language Guide (2nd Edition) - November 9, 2007 • Hans Boehm, POPL 2003 • Hans Boehm, TS-3281, 2005 JavaOneSM conference } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Agenda • Conceitos de Garbage Collection • Dicas de programação • Problemas com finalização • Usando referências de objeto • Evitando Memory Leak • Conclusão Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Referências de Objetos • Propósito • Ganchos de eventos post-mortem, mais flexíveis que finalização. • 3 tipos de referencias • Referencias fracas (Weak) • Referencias leves (Soft) • Referencias fantasma (phantom) • Todas as 3 ajudam o GC a decidir quando uma referência a um objeto não é mais utilizada de forma bastante efetiva. • Através do gerenciamento de uma fila de referencias. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Referências Fracas ref = new WeakReference(obj, rq); Referência Referente Ref obj Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Referências Fracas A referencia foi colocada na fila de referencias GC encontrou o referente “morto” e coletou a referencia Referência Referente Ref obj Fila de Referencias rq Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Referências Fracas • Utilização • Avise-me se o objeto referente for coletado pelo GC • Apenas esta referencia não impede a coleta do objeto pelo GC. • get() retornará • O referente, caso não tenha sido coletado • Null, caso contrário • O objeto referente será coletado pelo GC Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
:-o Finalização • É uma forma flexível de se implementar finalização. • Prioriza a finalização do objeto • Objetos não serão considerados para “finalização” • Operação não afetada pela fila de finalização da VM • http://www.devx.com/Java/Article/30192 Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Referências Leves • Utilização • Apenas colete este objeto se houver pressão por memória. • get() retornará • O referente, caso não tenha sido coletado • Null, caso contrário • O referente será coletado pelo GC Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Referências Leves • Cuidado ! Você deve ser um desenvolvedor malicioso para utilizar esta política de referencia. • O que é acessível a partir de cada referencia ? • Quanto é caro para recriar ? • Como tomar decisões se não temos uma pista de quais objetos foram coletados e quando. • OK para caches rápidos e simples. • Mas lembre-se de criar referências fortes para dados que devem ser “persistentes” ou lembrados mais pra frente. Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Referências Fantasma • Utilização • Deixe alguns dados acessíveis depois que o objeto referente tenha sido coletado, para que o desenvolvedor utilize estes dados para limpeza de recursos do objeto. • get() retornará • Null, sempre • O referente não será coletado pelo GC, até que ... • Explicitamente liberado pelo usuário • O objeto referente está inacessível Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Agenda • Conceitos de Garbage Collection • Dicas de programação • Problemas com finalização • Usando referências de objeto • Evitando Memory Leak • Conclusão Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
O Que É Memory Leak? • Garbage collector irá coletar todos objetos não alcançáveis • Porém, não coletará os objetos que ainda forem alcançáveis • Memory leak no heap • Objetos que são alcançáveis, mas não utilizados • Retenção não intencional de objetos Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Tipos de Memory Leak • Memory leak “tradicionais” • Fácil identificação • Memória começa a aumentar, aumentar e aumentar • OutOfMemoryError • Memory leak “temporário” • O uso da memória heap fica temporariamente muito grande, depois diminui • Aumento da frequência de coletas Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Fontes de Memory Leak • Objetos em um escopo errado • Listeners • Exceções mudando o fluxo de controle • Falta de gerenciamento de metadados Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Objetos em um escopo errado (1/2) • Abaixo, o array alunos é acessado apenas dentro do método processar() • Não será recuperado enquanto a instância de Sala estiver ativa class Sala { private String[] alunos; public void processar(int tamanho) { if(alunos == null || alunos.length <tamanho) alunos = new String[tamanho]; preencher(alunos); imprimir(alunos); } } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Objetos em um escopo errado (2/2) • Lembre-se • GC geracional adora objetos de vida curta class Sala { public void processar(int tamanho) { String[] alunos = new String[tamanho]; preencher(alunos); imprimir(alunos); } } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Listeners (1/2) • Event Listeners (Swing, AWT, etc) { ImageReader reader = new ImageReader(); cancelButton.addActionListenner(reader); reader.readImage(inputFile); // reader é ainda alcançável tão logo // cancelButton permaneça alcançável } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Listeners (2/2) • Precisamos removê-lo explicitamente • Quando o objeto listener nunca mais for usado • Disparo de exceções pode mudar o fluxo de controle try { ImageReader reader = new ImageReader(); cancelButton.addActionListenner(reader); reader.readImage(inputFile); cancelButton.removeActionListener(reader); }catch ( IOException e) { // Se for gerado por readImage(), reader // não será removido do conjunto de // listeners de cancelButton } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Exceções mudando o fluxo de controle • Sempre use blocos finally ImageReader reader = new ImageReader(); cancelButton.addActionListenner(reader); try { reader.readImage(inputFile); }catch ( IOException e) { ...... } finally { cancelButton.removeActionListener(reader); } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Falta de gerenciamento em Metadados • Algumas vezes, queremos • Rastrear metadados de objetos • Manter separado em um map class ImageManager { private Map<Image,File> map = new HashMap<Image,File>(); public void add(Image image, File file) { ... } public void remove(Image image) { ... } Public File get(Image image) { ... } } Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis
Falta de gerenciamento em Metadados • O que acontece se o método remove(image) não for chamado ? • A imagem e o arquivo nunca serão removidos do map • Forma muito comum de memory leak • Nós queremos • Que o map perceba que a chave não é mais alcançável • Apague a respectiva entrada • É exatamente o que WeakHashMapfaz: private Map<Image,File> map = new WeakHashMap<Image,File>(); Créditos para J1 TS-2906: John Coomes, Peter Kessler, Tony Printezis