allocation mémoire en perl

Le
Math
Bonjour,

J'aimerai votre avis sur mon cas

En fait, j'ai un script perl qui tourne en boucle, mais je dois l'arreter
au bout d'une heure environ, sinon, il consomme trop de ressources ; au
démarrage : 14Mo, et au bout de 3 minutes, il est déjà à 20Mo, et cela
augmente assez rapidement !

Donc, j'ai certainement une erreur quelque part, mais où !!?? parmis 5
fichiers, et plusieurs milliers de lignes (au total)

J'ai une classe (obj), puis dans un autre fichier perl, j'ai une boucle :

foreach my $ob (@list) {
my $obj = obj->new();
$obj->function($ob);
}

Pour le premier élément de @list, une variable $ob est créée et elle
est égale à la valeur du premier élément de @list. Mais ensuite, pour
le deuxième élément, que deviens le précédent $ob ? son allocation
mémoire est supprimée ? ou alors elle persiste toujours ? Je ne sais pas
si mon probleme viens de là, mais comme je ne comprends pas tres bien ce
comportement, j'ai du mal à trouver mon erreur.

J'ai essayé de mettre un undef($obj) avant la fin du foreach, mais cela
ne change rien
  • Partager ce contenu :
Vos réponses
Trier par : date / pertinence
espie
Le #129786
In article Math
Bonjour,

J'aimerai votre avis sur mon cas...

En fait, j'ai un script perl qui tourne en boucle, mais je dois l'arreter
au bout d'une heure environ, sinon, il consomme trop de ressources ; au
démarrage : 14Mo, et au bout de 3 minutes, il est déjà à 20Mo, et cela
augmente assez rapidement !

Donc, j'ai certainement une erreur quelque part, mais où !!?? parmis 5
fichiers, et plusieurs milliers de lignes (au total)...


Devel::Size est ton ami, recupere-le sur CPAN, et utilise-le jusqu'a
determiner ou est le probleme.

Un petit peu d'aide de Scalar::Util, en particulier la fonction weaken()
peut etre extremement utile pour aider le GC a faire son boulot sur les
structures cycliques.

Paul Gaborit
Le #129784
À (at) Sat, 14 Oct 2006 15:19:21 +0200,
Math [...]
J'ai une classe (obj), puis dans un autre fichier perl, j'ai une boucle :

foreach my $ob (@list) {
my $obj = obj->new();
$obj->function($ob);
}

Pour le premier élément de @list, une variable $ob est créée et elle
est égale à la valeur du premier élément de @list. Mais ensuite, pour
le deuxième élément, que deviens le précédent $ob ? son allocation
mémoire est supprimée ? ou alors elle persiste toujours ? Je ne sais pas
si mon probleme viens de là, mais comme je ne comprends pas tres bien ce
comportement, j'ai du mal à trouver mon erreur.

J'ai essayé de mettre un undef($obj) avant la fin du foreach, mais cela
ne change rien


(Je réponds juste sur ce point. Pour le reste la réponse de Marc Espie
convient parfaitement.)

Dans un foreach, la variable de boucle est un *alias* de l'élément
courant. Donc votre variable $ob n'occupe quasiment pas de mémoire
(pas plus qu'un simple scalaire) et ce n'est pas une copie des
différents éléments de votre liste (qui existent déjà) mais bien un
*alias*. Ce qui signifie que toute modification sur $ob modifie
réellement l'élément contenu dans le @list.

La portée d'une déclaration 'my' est celle du bloc englobant (ici le
contenu de la boucle). À chaque passage sur la ligne contenant le
'my', la variable $obj est allouée puis elle est détruite à la fin de
ce passage dans la boucle. Votre appel à undef() est donc inutile.

Il vaut mieux chercher ailleurs... À moins que votre classe 'obj' crée
des cycles de références a priori non gérables (sans aide explicite du
programmeur) par le gestionnaire de mémoire de perl.


--
Paul Gaborit - Perl en français -
Math
Le #129782
Le Mon, 16 Oct 2006 09:55:11 +0200, Paul Gaborit a écrit :

Dans un foreach, la variable de boucle est un *alias* de l'élément
courant. Donc votre variable $ob n'occupe quasiment pas de mémoire
(pas plus qu'un simple scalaire) et ce n'est pas une copie des
différents éléments de votre liste (qui existent déjà) mais bien un
*alias*. Ce qui signifie que toute modification sur $ob modifie
réellement l'élément contenu dans le @list.


Merci pour cette réponse !


La portée d'une déclaration 'my' est celle du bloc englobant (ici le
contenu de la boucle). À chaque passage sur la ligne contenant le
'my', la variable $obj est allouée puis elle est détruite à la fin de
ce passage dans la boucle. Votre appel à undef() est donc inutile.


ok, je vais "alléger" ou plutot "rendre plus lisible" mon script alors en
enlevant ces undef().


Il vaut mieux chercher ailleurs... À moins que votre classe 'obj' crée
des cycles de références a priori non gérables (sans aide explicite du
programmeur) par le gestionnaire de mémoire de perl.


je ne comprends pas très bien ce dernier paragraphe... qu'est ce qui est
"non gérable" ? (mis à part les erreurs que je fais ! :-) )

Math
Le #129781
Le Sat, 14 Oct 2006 16:54:53 +0000, Marc Espie a écrit :

Devel::Size est ton ami, recupere-le sur CPAN, et utilise-le jusqu'a
determiner ou est le probleme.


OK, sauf que le cpan à tjs des problèmes avec moi (avec une fedora ca
marchait parfaitement, mais depuis que je suis avec ubuntu, le cpan ne
fonctionne pas vraiment)

J'ai tout de même réussi à l'installer. Il me reste plus qu'a trouver
la variable qui prends du poids...

Paul Gaborit
Le #129780
Le Mon, 16 Oct 2006 09:55:11 +0200, j'écrivais :

Il vaut mieux chercher ailleurs... À moins que votre classe 'obj' crée
des cycles de références a priori non gérables (sans aide explicite du
programmeur) par le gestionnaire de mémoire de perl.



À (at) Tue, 17 Oct 2006 12:57:46 +0200,
Math

je ne comprends pas très bien ce dernier paragraphe... qu'est ce qui est
"non gérable" ? (mis à part les erreurs que je fais ! :-) )


Ce qui n'est pas géré automatiquement par perl, c'est la libération
des bouts de mémoire alloués dynamiquement contenant des cycles de
références.

Exemple de script qui fait exploser la mémoire :

------ A NE PAS FAIRE --------
while(1) {
my %h = (a => "a" x 10000); # pour remplir la mémoire un peu plus vite...
$h{b} = %h; # on crée un cycle !
# ... des trucs ...
}
------------------------------

La table de hachage associée à %h (et son contenu) devrait disparaître
à la fin de chaque passage dans la boucle. Mais il n'en est rien. Car
elle contient un référence à elle-même (un cycle de références) et
perl ne peut pas détecter que ce cycle n'est plus relié à rien.

Pour éviter cela, il faut d'une part savoir quand on crée un cycle et
d'autre part ne pas oublier de le casser explicitement lorsqu'on n'en
a plus besoin, pour que perl puisse récupèrer la mémoire.


-------- OK (mais inutile) ---
while(1) {
my %h = (a => "a" x 10000); # pour essayer deremplir la mémoire...
$h{b} = %h; # on crée un cycle...
# ... des trucs ...
undef $h{b}; # ...mais on le casse explicitement.
}
------------------------------

Ce n'est pas toujours évident de savoir qu'on crée un ou plusieurs
cycles. Surtout si on ne maîtrise pas complètement les mécanismes de
référence en Perl.

Heureusement, on peut détecter et contrôler ce genre de choses. Par
exemple en utilisant l'un des modules Devel::Cycle,
Test::Memory::Cycle ou Devel::WeakRef. Tous sur CPAN.

--
Paul Gaborit - Perl en français -

Math
Le #131369
Le Sat, 14 Oct 2006 16:54:53 +0000, Marc Espie a écrit :

Bon, je commence à craquer ! cela fait un bout de temps que je cherche
cette foutu fuite mémoire, sans la trouver...

J'ai eut une piste à un moment, et puis...
j'ai une variable qui augmente, mais c'est un compteur, et ca augmente de
quelque octets à chaque fois. En fait c'est le $compteur :
$compteur=0;
foreach my $ob (@list) {
my $obj = obj->new();
$obj->function($ob);
$compteur++;
}

Bon, je suis pret à "preter" mon script si une âme sympatique aurai la
volonté/grâce/gentillesse/amabilité de m'aider.

Je sais bien que c'est beaucoup demander, mais on sais jamais...

Pour me contacter en direct :
m . lory at free . fr (sans les espaces et at=@)

Merci
Poster une réponse
Anonyme