2010-06-04 6 views
12

Contrairement à Java, Perl utilise le nombre de références pour la récupération de place. J'ai essayé de chercher des questions précédentes qui parlent de C++ RAII et de pointeurs intelligents et Java GC mais n'ont pas compris comment Perl traite le problème de référencement circulaire.Garbage collection in Perl

Quelqu'un peut-il nous expliquer comment le garbage collector de Perl gère les références circulaires? Est-il possible de récupérer de la mémoire circulaire référencée qui n'est plus utilisée par le programme ou est-ce que Perl ignore tout simplement ce problème?

Répondre

13

Selon ma copie de Programming Perl 3rd ed., à la sortie Perl 5 fait une "marque et un balayage coûteux" pour récupérer des références circulaires. Vous voudrez éviter autant que possible les références circulaires car sinon elles ne seront pas récupérées avant la sortie du programme.

Perl 5 offre des références faibles via le module Scalar::Utils.

Perl 6 passera à un schéma collecté garbage collable (bien, le underlying VM will have multiple garbage collection options et le comportement de ces options peuvent avoir un effet sur Perl). C'est-à-dire, vous serez en mesure de choisir entre différents éboueurs, ou de mettre en œuvre votre propre. Vous voulez un collecteur de copie? Sûr. Vous voulez un collecteur de couleurs? Tu l'as eu. Marquer/balayer, compacter, etc? Pourquoi pas?

+4

Nit: Perl 5 utilise le comptage de référence. C'est un système de collecte des ordures. – tsee

+0

OK, j'ai modifié la référence à Perl 6 garbage collection. –

+1

Merci d'avoir mis à jour la réponse. NB: Les éboueurs enfichables semblent être une idée horrible. Une excellente façon de ralentir les choses et/ou de produire une action douteuse à distance en branchant des éboueurs qui font des promesses différentes sur le temps du GC. – tsee

-8

Perl applique un GC alternatif mark-and-sweep dans certaines occasions (lorsqu'un thread meurt, je pense) afin de récupérer des références circulaires. Notez que la strophe "chaque valeur est une chaîne" rend difficile la création de véritables références circulaires; c'est faisable, mais pas le code Perl "normal", c'est pourquoi le comptage des références fonctionne bien avec Perl.

+0

Façon rapide de fuir un appel perl SV 'sub leak {my $ r; $ r = \ $ r; } ' Bien que ce soit un exemple artificiel, il n'est pas difficile de faire l'équivalent sans le remarquer. –

+7

C'est complètement faux; Perl ne * croit * pas que chaque valeur est une chaîne. 'my $ hashref = {a => 1};' laisse '$ hashref' comme référence réelle, pas de chaîne. Cela est vrai depuis Perl 5, sorti en octobre ** 1994 ** - il y a 17 ans. (Bien sûr, Perl convertira heureusement la référence en une chaîne, mais cette conversion est unidirectionnelle) – derobert

2

La réponse rapide est que Perl 5 fait pas gérer automatiquement les références circulaires. Sauf si vous prenez des mesures explicites dans votre code, aucune de vos structures de données qui incluent des références circulaires ne sera récupérée tant que le thread qui les a créées ne meurt pas. Ceci est considéré comme un compromis acceptable en ce sens qu'il évite le besoin d'une récupération de place à l'exécution qui ralentirait l'exécution. Si votre code crée des structures de données avec des références circulaires (ie un arbre dont les nœuds contiennent des références à la racine), vous voudrez utiliser le module Scalar :: Util pour "affaiblir" les références qui pointent vers la racine nœud. Ces références faibles n'ajouteront pas au compte de référence de ce qu'elles pointent vers, de sorte que toute la structure de données sera automatiquement désaffectée lorsque la dernière référence externe disparaîtra.

Exemple:

use Scalar::Util qw(weaken); 

... 

    my $new_node = { content => $content, root => $root_node }; 
    weaken $new_node->{root}; 
    push @{$root_node->{children}}, $new_node; 

Si vous utilisez le code comme ceci chaque fois que vous ajoutez de nouveaux noeuds à votre structure de données, puis les seules références à la racine qui sont effectivement comptés sont ceux de l'extérieur de la structure. C'est exactement ce que vous voulez. Ensuite, la racine, et récursivement tous ses enfants, seront récupérés dès que la dernière référence externe disparaîtra.