Perl utilise un algorithme de comptage de références pour gérer automatiquement la mémoire : chaque variable possède un compteur de références. Lorsque le compteur atteint zéro, la mémoire est libérée. Dans la plupart des cas, cela fonctionne de manière transparente — les variables inutilisées sont supprimées dès qu'elles sortent du contexte.
Le problème survient avec les références circulaires (par exemple, un objet se référant à lui-même ou deux structures se référant l'une à l'autre). Dans ce cas, le compteur de références ne sera jamais égal à zéro, et la mémoire ne sera pas libérée.
Pour prévenir les fuites, le module Scalar::Util::weaken est utilisé — il permet de créer des références « affaiblies » qui n'augmentent pas le compteur de références.
Exemple :
use Scalar::Util qw(weaken); my $a = {}; my $b = { ref => $a }; $a->{ref} = $b; weaken($a->{ref}); # maintenant, il n'y a plus de dépendance forte circulaire
Est-il correct de dire que Perl libère toujours automatiquement toute la mémoire inutilisée, même en présence de structures interconnectées complexes ?
Réponse et exemple :
Non ! En cas de références circulaires, Perl ne pourra pas libérer la mémoire automatiquement sans utiliser weaken :
my $a = {}; $a->{self} = $a; # cycle # $a ne sera jamais supprimé automatiquement — un débranchement manuel ou un affaiblissement de référence sera nécessaire
Histoire 1 : Sur un grand service web Perl, il y avait une fuite de mémoire — les sessions des utilisateurs stockaient des références les unes aux autres dans un hachage, et personne n'utilisait les références affaiblies. Le service consommait toutes les ressources en une journée, se figeait et nécessitait des redémarrages.
Histoire 2 : Un ORM fait maison créait des cycles entre les objets User et Group, chacun d'eux se référant à l'autre. Après avoir quitté le contexte, les objets restaient en mémoire — le service gonflait progressivement jusqu'à des dizaines de gigaoctets !
Histoire 3 : L'utilisation de sous-programmes anonymes (« closures ») comme méthodes de classe, référencant
$self, entraînait des fuites à chaque création d'objet, jusqu'à ce qu'un analyseur identifie les références circulaires et indique le besoin d'utiliserweaken.