2010-09-27 13 views
20

Comment supprimer complètement un paquet en Perl? Cela signifie non seulement les variables du paquet, mais aussi toutes les tables magiques que Perl met à jour pour gérer les changements d'héritage et d'autres choses.Comment puis-je supprimer complètement un paquet en Perl?

Ce test simple:

use warnings; use strict; 
use Test::LeakTrace; 
use Symbol 'delete_package'; 

leaktrace { 
    package test; 
    our $x = 1; 

    package main; 
    delete_package 'test'; 
}; 

résultats dans la sortie suivante:

leaked ARRAY(0x81c930) from /lib/perl5/5.10.1/Symbol.pm line 166. 
leaked HASH(0x827760) from /lib/perl5/5.10.1/Symbol.pm line 166. 
leaked SCALAR(0x821920) from /lib/perl5/5.10.1/Symbol.pm line 166. 

Utilisation du drapeau -verbose pour leaktrace résultats dans des données-écrans, je peux poster sur demande.

Les choses empirent si la ligne our @ISA = 'main'; est ajouté au package test:

leaked ARRAY(0x81cd10) from so.pl line 32. 
leaked SCALAR(0x81c930) from so.pl line 32. 
leaked ARRAY(0x8219d0) from so.pl line 32. 
leaked HASH(0x8219c0) from so.pl line 32. 
leaked SCALAR(0x8219b0) from so.pl line 32. 
leaked HASH(0x8219a0) from so.pl line 32. 
leaked SCALAR(0x821970) from /lib/perl5/5.10.1/Symbol.pm line 161. 
leaked HASH(0x821950) from so.pl line 32. 
leaked SCALAR(0x821940) from so.pl line 32. 

ligne 32 est l'endroit où le our @ISA est.

Pour illustrer que ceux-ci sont en effet des fuites et non seulement le bruit de l'interprète:

my $num = 0; 
while (1) { 
    no strict 'refs'; 
    @{$num.'::ISA'} = 'main'; 
    delete_package $num++; 
} 

mangera la mémoire à un taux constant

Alors, est-il une meilleure façon de se débarrasser d'un paquet que le du symbole? Y a-t-il autre chose que je dois faire pour l'aider?

J'ai vu le même comportement dans 5.8.8, 5.10.1 et 5.12

+0

Une grande question, ma curiosité est piquée, mais je dois demander: Pourquoi? –

+5

Dans mon module 'List :: Gen' sur CPAN, (http://search.cpan.org/perldoc?List::Gen), j'ai une fonction d'utilité' curse' qui installe un objet basé sur la fermeture dans un paquet temporaire (pour faciliter les appels de méthode standard (à haute vitesse)). 'delete_package' nettoie tout, mais' malédiction 'perd toujours de la mémoire en raison des problèmes ci-dessus. La fuite n'est pas énorme, mais elle est là, et j'aimerais la brancher si possible. –

+3

Si vous ne l'avez pas déjà fait, envoyez-le en tant que bogue perl. – ysth

Répondre

4

Donc c'est un bug dans perl, un rapporté un comme vous avez découvert. En dehors de cela, il semble que votre seul moyen d'éviter ces fuites est de choisir une autre approche pour résoudre votre problème. Pourquoi avez-vous besoin d'un paquet semi-anonyme au lieu, par exemple, d'une fermeture? Ceux-ci sont assez faciles à ne pas fuir, et, avec une certaine créativité, vous pouvez toujours implémenter pratiquement toutes les interfaces externes, par exemple en bénissant vos coderefs de fermeture et en leur fournissant des méthodes, en les surchargeant, etc.

+0

En raison de la façon dont ces objets sont utilisés (calculs de boucle interne serrés), j'essaie d'éviter plusieurs niveaux de redirection. Donc 'curse' installe ses objets dans un paquet de sorte que vous pouvez appeler' $ obj-> method' (et conserver un semblant d'héritage) plutôt que d'exposer l'implémentation: '$$ obj {méthode}()'. Je pourrais utiliser 'AUTOLOAD' ou l'installation de méthodes de stub dans une classe parente, mais dans chaque cas il y aurait au moins un appel de sous-programme supplémentaire, et au moins une recherche de hachage par appel. –

+0

Je ne pense pas que les paquets semi-anonymes soient un bon moyen d'optimiser ce genre de choses. Pour un, les appels de méthode, même en tant que perl caches, la résolution de la méthode après le premier appel, sont un peu plus lents que les appels simples à un coderef.De plus, transmettre des arguments à une fonction est sensiblement plus lent que de construire un coderef qui se ferme sur les arguments dont il a besoin. Et quand j'ai dit "objet", je ne voulais pas non plus que vous utilisiez '$$ obj {méthode}()', mais bénis le coderef lui-même. En outre, l'utilisation de 'AUTOLOAD' semble être une mauvaise façon d'optimiser les boucles internes serrées - c'est ** lent **. – rafl

+0

Les méthodes AUTOLOAD et stub sont déjà exclues pour les raisons mentionnées dans mon premier commentaire. Cependant, j'ai encore besoin de fournir une sorte d'interface à l'utilisateur final car il existe de nombreuses méthodes qui peuvent être appelées sur un objet. La méthode la plus rapide (temps d'exécution, pas le temps de création) que j'ai trouvé est d'installer les méthodes basées sur la fermeture dans des paquets anon et de fournir ensuite une référence bénie dans ce paquet. jetez un oeil à 'List :: Gen :: curse' et à l'implémentation de ses générateurs pour un exemple. Si vous avez un meilleur moyen de l'optimiser, laissez-moi savoir –