Desenvolvimento - Java

Garbage Collector e as Armadilhas na Performance de Aplicações

De um lado, os coletores ajudam na manipulação de acesso a memória. Do outro, podem comprometer a confiabilidade de seu produto final...

por Eric C M Oliveira



O gerenciamento de memória é um complexo campo da ciência da computação e existem várias técnicas para torná-la mais eficiente. Seu problema mais comum é o vazamento de memória, que ocorre quando uma quantidade de memória é alocada e não é liberada ainda que nunca seja utilizada.

Em plataformas de desenvolvimento que possuem um modelo de gerenciamento de memória manual, isto ocorre quando objetos perdem a referência sem terem sido liberados, mantendo o uso do espaço de memória. Já nas plataformas que possuem memória gerenciada, como é o caso de Java e .NET, isto ocorre apenas por não terem sido liberadas as referências aos objetos alocados.

Uma fonte de problemas comuns em aplicações desenvolvidas nessas plataformas está relacionada justamente ao modelo de gerenciamento de memória. A tecnologia de gerenciamento de objetos na memória, conhecida como Garbage Collector, é uma vantagem para o desenvolvedor pois não o obriga a manipular diretamente o acesso à memória do computador, mas é justamente aí que residem as principais armadilhas para a performance e confiabilidade das aplicações.

Gerenciamento de Memória

O gerenciamento de memória é normalmente dividido em três áreas: hardware, sistema operacional e aplicação. Em termos de aplicações, envolve a quantidade de memória necessária para estruturas de dados, armazenamento de objetos e também a liberação de recursos / memória para reuso em outras transações.

O gerenciamento de memória está relacionado a duas tarefas:

  • alocação: quando o programa requisita um bloco de memória, o gerenciador disponibiliza esse bloco para a alocação;
  • reciclagem: quando um bloco de memória foi alocado, mas os dados não foram requisitados já há algum tempo e, esse bloco pode ser reusado para outra requisição.

Existem dois ramos a considerar: ou o desenvolvedor escolhe quando liberar esses blocos, chamado de gerenciamento manual, ou há um gerenciador automático para essa função.

Aqui podemos observar o problema básico do gerenciamento de memória, que é conhecer quando manter ou não um bloco de memória em atividade.

Em linguagens de programação orientadas a objetos, a criação de objetos é um processo que determina a ocupação dinâmica de muitos pequenos segmentos de memória. Se esse espaço não fosse devolvido para reutilização pelo sistema, a dimensão de aplicações desenvolvidas com linguagens de programação orientadas a objetos estaria muito limitada.

Garbage Collector ou Coletores

O gerenciamento automático de memória, conhecidos como garbage collector ou simplesmente coletores, é um serviço, que automaticamente, libera blocos de memória que não serão mais usados em uma aplicação.

As vantagens desse tipo de gerenciamento são:

  • liberdade do programador que não esta mais obrigado a ficar atento a detalhes de memória;
  • há menos bugs de gerenciamento de memória;
  • gerenciamento automático é mais eficiente que o manual.

Entre as desvantagens, podemos citar:

  • desenvolvedor tende a estar mais desatento em relação a detalhes de memória;
  • gerenciador automático apresenta limitações.

Um objeto está apto a ser usado pelo garbage collector quando não há mais referências a esse objeto.

O ambiente .NET e Java tem o garbage collector que periodicamente libera memória usada por objetos que estão há algum tempo sem serem referenciados. Essa atividade é automática, entretanto, em algumas situações, o desenvolvedor pode querer executar o coletor explicitamente, chamando o método gc. Por exemplo, você poder querer executar o garbage collector após um setor de código que cria um grande número de objetos que não serão usados mais ou antes de uma área de sua aplicação que necessitará muita memória disponível.

Erros de Acesso a Memória

Os problemas de execução de sistemas podem estar relacionados a erros de vazamento memória, isto é, quando uma quantidade de memória é alocada e não é liberada ainda que nunca seja utilizada.

Os erros de acesso à memória podem ser divididos em duas categorias:

  • Erros de acesso à memória: corrompe o conteúdo de memória e pode causar erros nos programas, retornar resultados errôneos, e comportamentos não previsíveis;

  • Erros de uso da memória(memory leak): causa vazamentos de memória que constantemente consomem recursos de memória, diminuindo a performance até que o sistema eventualmente aborte.

Conclusões

O problema primário dos Garbage Collector reside na natureza de como esta tecnologia entra em ação. O ciclo de uma retirada de objetos da memória pode ocorrer a qualquer tempo e pode requerer um tempo arbitrariamente longo para se completar e, conseqüentemente, ocupar tempo de processamento que seria valioso para a aplicação.

Outro grande problema é que a quantidade de objetos a serem coletados pode crescer muito rapidamente antes da limpeza da memória entrar em ação, ou ainda, a ação da coleção de objetos não surtir efeito por causa do padrão de programação utilizado. Em outras palavras, a alocação de objetos na memória que não são utilizados e nunca perdem a referência, ou a montagem de estruturas muito grandes de objetos na memória, caracterizam a principal fonte de problemas de falta de memória e lentidão de aplicações em aplicações Java e .NET, o vazamento de memória.

São problemas comuns de memory leaks:

  • Leitura e escrita fora do limite de Arrays;
  • Acesso a memória não inicializada;
  • Acesso a memória liberada;
  • Liberação de memória livre ou inválida.

Caracteriza-se como a tecnologia responsável pelo gerenciamento de objetos na memória. Entretanto isso não significa que o desenvolvedor não deva mais se preocupar com o vazamento de memória. O Garbage Collector não tem como perceber sempre que não está usando algum objeto, dando assim margem para um vazamento de memória ou memory leak.

É importante salientar que os desenvolvedores não tem como atuar explicitamente sobre esse processo. No entanto, é possível remover explicitamente a referência a um objeto para sinalizar ao Garbage Collector que o objeto não é mais necessário e pode ser removido; ou sugerir ao sistema que execute o garbage collector através da invocação ao método gc() da classe java.lang.System, no caso da plataforma Java.

Eric C M Oliveira

Eric C M Oliveira - Bacharel em Ciencia da Computação/FASP e Comunicação/Unesp, tem experiência em desenvolvimento Java nas plataformas J2SE, J2EE e J2ME, além de atividades ligadas a disciplina de testes, engenharia e qualidade de software. Tem certificações Java SCJP 1.3, SCJP 1.4, Rational Test Management, Rational Robot e RUP (Rational Unified Process).