Uso compulsivo de memória

8:50 am Desenvolvimento, Memória

As vezes escutamos afirmações do tipo: “Vazamentos de memória são comuns em linguagens baixo nível. Coisas do passado. Linguagens modernas estão livres desse pesadelo.” Quem acredita nisso também deve acreditar em coelhinho da Páscoa, Papai Noel e certamente em “almoço grátis”. Linguagens “modernas” que utilizam gerenciamento próprio do espaço de memória no processo (como Java e .Net) também podem produzir vazamentos de memória ou sofrer com o mau uso da memória. Claro que não tão frequentes quanto em C ou C++, mas essas linguagens também permitem a construção de sistemas ou componentes com um consumo de memória sempre crescente, contra a vontade do desenvolvedor.

Lembro-me de que nos longínquos anos 90, quando falavam de Java a performance era o ponto mais questionado. Com o passar do tempo e a evolução do hardware, esse ponto foi deixado de lado. Hoje o comentário sobre sistemas em Java mais comum é que “consomem muita memória”. Mas algumas vezes, isso apenas mascara para o cliente o verdadeiro problema: vazamento de memória.

Durante minhas experiências profissionais já vi soluções brilhantes (e outras nem tanto) para vazamentos de memória. Algumas específicas para uma ou outra arquitetura ou ambiente, outras genéricas (de uso geral). Fazendo uma analogia com o mundo palpável, vamos supor que um vazamento de memória seja uma torneira gotejando sobre um balde. Se o balde entornar, o cliente pode ficar muito bravo. Vamos então a alguns exemplos de soluções para nossa torneira:

  • Aumento de memória: No mundo das grandes corporações, a primeira e mais comum solução é aumentar o tamanho do balde! Isso é fácil, barato, e de rápida implementação e de resultado instantâneo: O que demorava 1 semana, agora demora 1 mês;
  • Restart da aplicação: Outra solução comum, quase tanto quanto a anterior nas grandes empresas. Durante a noite, quando geralmente o gotejar é mais lento, você pega o balde, corre e joga a água fora em um lugar apropriado. Um ponto importante é que tem que ser rápido o suficiente pra fazer o trabalho entre uma gota e outra. Caso contrário algumas gotas caem no chão. Mas o cliente pode nem perceber o piso molhado.
  • Bloquear o acesso ao módulo: se não for uma torneira útil, você pode simplesmente fechar o registro para esta tubulação. Se alguém precisar da torneira, que use a de outro lugar.
  • Liberação de memória logo após a alocação: Isso só é possível em alguns ambientes e sistemas (por exemplo, os feitos em C). É difícil de imaginar, mas existe! Trocamos o balde por cachorro, treinado, jeitoso e delicado (por exemplo um dog alemão) pra beber as gotas de água que goteja. O cão pode ficar ali durante horas. E funciona bem. Mas ele vai sair do lugar, pra realizar outras necessidades, ou porque deu vontade mesmo. Que a água vai pingar no chão vai, mas ninguém saberá exatamente quando nem quanto.
  • Resolver o vazamento de memória: Essa é a última solução. Muita gente acredita que a hora do bombeiro é cara, outros acham que a torneira já está muito velha mesmo, e a solução seria trocar todo o encanamento. As vezes a solução não compensa mesmo. Mas algumas vezes a torneira está vazando por um motivo simples : não foi fechada direito. Outros casos podem ser mais complicados: seu mecanismo interno está estragado, foi montada com peças de má qualidade ou foi montada com peças de boa qualidade, mas foi montada de forma errada.

Para resolver vazamentos ou mau uso de memória uma ferramenta de qualidade é indispensável. Depois de entender o fluxo de execução do sistema ou componente, a utilização de ferramentas de profiling nos dá o “mapa da mina”. Dentre as existentes, duas que merecem destaque são:

- YourKit: para sistemas desenvolvidos em Java e C#, uma ferramenta de grande utilidade é um profiler como o YourKit, já comentado em um post anterior. O YourKit possui um recurso excelente pra procurar por vazamentos de memória e mesmo analisar sua utilização após o start: é possível criar snapshots da memória do processo para uma posterior verificação. Sem degradação da performance do sistema, este recurso em algumas situações pode ser usado inclusive no ambiente de produção.

- Valgrind: é a ferramenta indicada para uso em sistemas desenvolvidos em C e C++. Com ele são detectados os pontos onde memória ou objetos alocados e “esquecidos” na memória, e também a distribuição do uso memória pelos objetos e módulos do sistema. Além de vazamentos de memória, é possível detectar um mal uso da memória do sistema. Mas o Valgrind é uma ferramenta pesada, impossível de ser utilizada em ambientes de produção.

Embora algumas vezes a correção do problema não é viável, sua identificação sempre é. Depois da compreensão do funcionamento de um módulo e o uso correto de ferramentas de análise de memória é possível identificar qualquer vazamento de memória. Mas qual decisão tomar com essa informação? Solucionar o problema, utilizar um “ajuste técnico de contorno” ou simplesmente deixar como está ? Isso já é trabalho da gerência.

1 Resposta
  1. Rafael Arcanjo :

    Date: abril 5, 2008 @ 10:32 am

    Olá Elvys,

    Gostei muito deste seu post e estou lendo outros aqui do blog.

    Cheguei aqui via Mundo.IT e já assinei o feed.

    Parabéns pela escrita e propriedade.

    Comentando sobre o assunto, realmente é um ponto complicado esta parte de memória nos aplicativos, que muitas das vezes é desenvolvido por gente que não é tão especializada e não sabe todas as artimanhas utilizadas para uma programação limpa.

    E os passos que tu mencionou são estes mesmo, principalmente o de reiniciar a aplicação. Lembra o que a gente faz quando o windows começa a travar ? Reinicia ! :)

    Vida longa e próspera.