[SP-pm] Memoria x Perl

Luis Motta Campos monsieur_champs em yahoo.com.br
Quinta Abril 6 04:43:48 PDT 2006


Lorn wrote:
> Rau mongers!
> 
> Estou com uma duvida, tem um programa em perl aqui na empresa, que 
> indexa documentos, e enquanto ele vai indexando a memoria vai caindo, e 
> no final, ele fica usando a memoria virtual, depois que o programa 
> termina ele não libera a memoria, eu acho ( tenho quase certeza ) que 
> não tem nada parecido com o free do C no perl, e eu acho também que o 
> linux deixar essa memoria no "buffer" pra acessar mais rapido se eu for 
> rodar o programa de novo, eu só queria confirmar isso, alguem já leu 
> alguma coisa sobre como é gerenciada a memoria no linux?
> 

   Lorn, isto fede a /memory leak/. Me parece que seu programa perl
comete dois erros muito importantes de alocação de memória:

   1. Aloca memória em ciclos, que nunca "perde referências" (e assim
não pode ser reclamada de volta pela máquina virtual do Perl)
   2. Aloca memória demais, sem implementar código minimamente
preocupado com isso.

   Vamos aos exemplos didáticos:

   Como o Perl Aloca Memória

   Como qualquer outra máquina virtual, a VM do Perl aloca memória para
os programas que interpreta em tempo de execução, conforme a necessidade
do programa e as estruturas de dados que este criar dinâmicamente.

   Como qualquer outra máquina virtual, a VM do Perl é totalmente
responsável pelo gerenciamento da memória alocada para os programas em
execução. O programador praticamente não precisa intervir neste assunto,
o que torna programar uma tarefa muito mais interessante, já que muitos
dos problemas relacionados com a programação são automágicamente
resolvidos pela máquina virtual do Perl.

   Claro, como toda boa solução, esta também tem desvantagens.
   A máquina virtual do Perl não consegue lidar muito bem com alocação 
cíclica de memória, por que usa um /garbage collector/ por copia. Sendo 
assim, quando o programador diz coisas como

   my $struct = { data => 2, struct => { data => 3, struct => undef } };
   $struct->{struct}{struct} = $struct;

   Criamos automaticamente uma referência cíclica para $struct.

   Quando acontece coisas como esta, a VM do Perl aloca memória sem 
dificuldade, mas simplesmente não consegue reclamar a memória de volta, 
por que existe sempre uma referência para o hash anônimo apontado por 
$struct, *mesmo* *quando* *dizemos*

   undef $struct;

   (Talvez exista um padrão como este nos teus scripts, Lorn).

   Para resolver isto, e ter certeza de que conseguiremos reclamar a 
memória de volta, precisamos quebrar o ciclo:

   $struct->{struct}{struct} = undef;
   undef $struct;

   Isto resolve o problema, fazendo com que o /garbage collector/ do 
perl seja capaz de perceber que as estruturas de dados apontadas por 
$struct não estão mais sendo utilizadas e podem ter sua memória reclamada.


   Agora vamos conversar sobre política de uso de memória por um programa.

   Quando um programa lê informações do mundo exterior (como da web ou 
de um banco de dados, por exemplo), normalmente não se preocupa com o 
tamanho da informação que está lendo.

   Isto é potencialmente um problema, conforme a quantidade de 
informações lidas aumenta. Afirmo isto por que, caso estejamos fazendo 
uma pergunta ao banco de dados por uma informação volumosa, podemos 
terminar com muitos gigabytes de memória alocada para muito pouca coisa.

   Por exemplo:

   my $dbh = DBI::connect( $dn, $user, $passwd ) or die $DBI::errstr;
   my $sth =
     $dbh->prepare( q{SELECT uid, name, login, password FROM user} );
   $sth->execute() or die $dbh->errstr;
   my @users = $sth->fetchall_arrayref({}) or die $dbh->errstr;

   Neste ponto, temos um problema potencial muito grave: se nossa base 
de dados tiver 30 usuários, vamos ler todos os dados e seguir sem problemas.

   Agora, se tivermos 300.000 usuários no banco de dados, isto vai 
custar *muita* memória. E vai demorar *muito*.

   Tá. Eu sei, meu exemplo é meio bobo, mas acho que o pessoal entendeu 
o problema. O importante é: não leia mais dados do que você vai 
precisar, especialmente quando está lendo de arquivos (que são muito 
mais perigosos que bancos de dados).

   Evite usar foreach() quando sabe que o conjunto de dados pode ser 
eventualmente grande, já que esta palavra chave do perl precisa alocar 
todos os elementos em memória antes de iterar sobre eles.

   Evite ler arquivos para arrays sem necessidade absoluta e inevitável.

   Em caso de problemas, consulte o seu guru.
   Chega, que eu já escrevi demais.
-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  Luis Motta Campos is Software Engineer, Oracle OCP/DBA, Un*x
  Sysadmin, Member of {Lisbon,São Paulo,Cascavel,Brasil,London}
  Perl Mongers and Perl Fanatic Evangelist
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=



		
_______________________________________________________ 
Yahoo! Acesso Grátis - Internet rápida e grátis. Instale o discador agora! 
http://br.acesso.yahoo.com


Mais detalhes sobre a lista de discussão SaoPaulo-pm