2010-09-27 20 views
20

Jak całkowicie usunąć pakiet w Perlu? Oznacza to nie tylko zmienne pakietu, ale także wszystkie magiczne tabele, które Perl aktualizuje, aby obsłużyć zmiany dziedziczenia i inne rzeczy.Jak mogę całkowicie usunąć pakiet w Perlu?

Ten prosty test:

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

leaktrace { 
    package test; 
    our $x = 1; 

    package main; 
    delete_package 'test'; 
}; 

wyniki w następujący wynik:

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. 

z flagą -verbose dla leaktrace skutkuje ekranów danych, które można zamieścić na życzenie.

Co gorzej, jeśli linia our @ISA = 'main'; dodaje do pakietu 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. 

Linia 32 jest gdzie our @ISA jest.

Aby zilustrować, że to rzeczywiście są przecieki, a nie tylko hałas od tłumacza:

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

zje pamięci ze stałą szybkością

tak, to czy istnieje lepszy sposób, aby pozbyć się pakietu niż symbol delete_package? Czy jest coś jeszcze, co muszę zrobić, aby mu w tym pomóc?

Widziałem to samo zachowanie w 5.8.8, 5.10.1 i 5.12

+0

Dobre pytanie, moja ciekawość jest wzbudzona, ale muszę zapytać: dlaczego? –

+5

W moim module 'List :: Gen' na CPAN, (http://search.cpan.org/perldoc?List::Gen), mam funkcję użyteczną' curse', która instaluje obiekt oparty na zamknięciu w pakiecie tymczasowym (w celu ułatwienia standardowych wywołań metod (z dużą prędkością)). 'delete_package' czyści wszystko, ale' curse' wciąż przecieka pamięć z powodu powyższych problemów. Wyciek nie jest ogromny, ale jest tam i chciałbym go podłączyć, jeśli to możliwe. –

+3

Jeśli jeszcze tego nie zrobiłeś, opisz to jako błąd perl. – ysth

Odpowiedz

4

Więc to jest błąd w Perl, zgłoszony jeden nawet jak odkryte. Bez tego, wydaje się, że jedynym sposobem uniknięcia tych przecieków jest wybranie innego podejścia do rozwiązania problemu.

Dlaczego potrzebujesz pół-anonimowego pakietu zamiast na przykład zamknięcia? Są one dość łatwe, aby nie przeciekać, a przy odrobinie kreatywności nadal można zaimplementować prawie każdy zewnętrzny interfejs na ich podstawie, na przykład poprzez błogosławieństwo swoich zamkniętych coderefów i zapewnić im metody, zapewniając przeciążenie dla nich, itp.

+0

Ze względu na sposób użycia tych obiektów (ścisłe obliczenia wewnętrznej pętli) staram się unikać wielu poziomów przekierowania. Tak więc 'curse' instaluje swoje obiekty w pakiecie, dzięki czemu możesz wywoływać' $ obj-> method' (i zachować trochę dziedziczenia), zamiast ujawniać implementację: '$$ obj {method}()'. Mogłabym użyć 'AUTOLOAD' lub instalacji metod kodu pośredniczącego w klasie nadrzędnej, ale w każdym przypadku byłaby to co najmniej 1 dodatkowe wywołanie podprogramu i co najmniej jedno wyszukiwanie hashowe dla każdego połączenia. –

+0

Nie sądzę, że pakiety pół-anonimowe to dobry sposób na optymalizację tego typu rzeczy. Po pierwsze, wywołania metod, nawet gdy Perl buforuje rozdzielczość metody po pierwszym wywołaniu, są nieco wolniejsze niż zwykłe wywołania do coderef.Dodatkowo przekazywanie argumentów do funkcji jest znacznie wolniejsze niż tworzenie coderefa zamykającego się na argumentach, których potrzebuje. A kiedy powiedziałem "obiekt", nie znaczyłem też, że używasz '$$ obj {method}()', ale błogosławiąc samego coderefa. Również użycie 'AUTOLOAD' w ogóle wydaje się złym sposobem optymalizacji ciasnych wewnętrznych pętli - jest to ** wolne **. – rafl

+0

Metody "AUTOLOAD" i stub są już wykluczone z powodów wymienionych w moim pierwszym komentarzu. Jednak nadal potrzebuję zapewnić pewien rodzaj interfejsu dla użytkownika końcowego, ponieważ istnieje wiele metod, które można wywołać na obiekcie. Najszybszą metodą, jaką znalazłem, jest zainstalowanie metod opartych na zamknięciu w pakietach anon, a następnie udostępnienie referencji pobłogosławionej w tym pakiecie. spójrz na 'List :: Gen :: curse' i implementację jego generatorów na przykład. jeśli masz lepszy sposób na zoptymalizowanie go, daj mi znać –

Powiązane problemy