gmpassos has asked for the wisdom of the Perl Monks concerning the following question:

I'm looking for the best way to cleanup a package.

I have a package FOO, where inside works a Safe compartment (from Safe.pm), and FOO need to be cleaned to be reused. All the stufs to make this need to be pure Perl and need to work from Perl 5.6.0+!

To do that I used Devel::Symdump to get the symbols table and created this function:

use Devel::Symdump ; my %clean_types = ( 'packages' => '::' , 'scalars' => '$' , 'arrays' => '@' , 'hashes' => '%' , 'functions' => '&' , 'ios' => '*' , ) ; my @clean_order = qw(scalars arrays hashes functions ios packages) ; sub clean_pack { my ( $pack ) = @_ ; my $dump = Devel::Symdump->rnew($pack); my %glob ; foreach my $i ( @clean_order ) { my $type = $clean_types{$i} ; my @symbols = $dump->$i ; foreach my $name ( @symbols ) { #print "$type$name\n" ; if ($type eq '\$') { undef $$name ;} elsif ($type eq '\@') { undef @$name ;} elsif ($type eq '\%') { undef %$name ;} elsif ($type eq '\&') { undef &$name ;} elsif ($type eq '\*') { undef *$name ;} elsif ($type eq '::') { $glob{"$name\::"} = 1 ;} $glob{$name} = 1 ; } } foreach my $Key ( reverse sort keys %glob ) { undef *$Key ;} }
There is a better way or module to do that?!

I really need to reuse the package to run the Safe compartment again! 1- because I need to clean the memory, 2- because I can't use a different name for the package.

My method works fine, but I think that Perl don't clean 100% of the memory! It cleans all the variables, functions, *ios and packages, but some bytes are still in use!

Graciliano M. P.
"The creativity is the expression of the liberty".

Replies are listed 'Best First'.
Re: better way to cleanup a package?
by shotgunefx (Parson) on Dec 03, 2002 at 08:59 UTC
    If you want to clear out a package, you could do the following...
    sub ERASE_PACKAGE { # Call with "Package::Name" my $packname = shift; $packname .= '::' unless $packname =~ /::$/; no strict "refs"; warn $packname; my $package = *{$packname}{HASH}; return unless defined $package; undef *{$packname . $_} foreach (keys %$package); }
    Many caveats. It's not good for unusing a module. See the above comments about @INC. Also it won't remove exported symbols. So if you export function Pack::Foo::foo(), the symbol table that it was exported to will still have foo() available after it's been erased.

    It can be useful for clearing out variables. I would only recommend it for situations such as that.

    -Lee

    "To be civilized is to deny one's nature."
      The problem with this way is the sub packages, and you don't clean the memory very well!
      Before to do a
      undef *{"scalarvar"}
      you need to do
      undef ${"scalarvar"}
      or the memory are not cleaned very well!

      And a package are only cleaned with:
      undef *{"packname::"}
      not with:
      undef *{"packname"}
      But you need to clean the variables and functions inside before!

      I made some tests of the reuse of 100 times of a package, with a randome variable with 50Mb, and it don't use more than 60Mb in the memory. But if I only do a undef *{"foovar"}, without undef ${"foovar"} first, the process use 100Mb!

      Graciliano M. P.
      "The creativity is the expression of the liberty".

        My tests show no difference in memory usage between undef *{"scalarvar"} and first undef ${"scalarvar"}. Perhaps you had a memory leak? My understanding is that Perl won't return the memory to the OS, just make it available to itself when freed. (Until the process terminates of course.)

        As far as not clearing out sub packages, I think of that as a feature. It would be rare enough to want to clear out a package in this manner, so my feeling is that if you would want clear out sub-packages (which may or may not have a relationship to the package being deleted) you should be explicit.

        -Lee

        "To be civilized is to deny one's nature."
Re: better way to cleanup a package?
by djantzen (Priest) on Dec 03, 2002 at 07:26 UTC

    As to your code, it seems to me you could do away with the %clean_types hashtable mapping as it doesn't do much, nor help with readability. <Update> Just use the value of $i and check for equality with 'scalars', etc. </Update>

    But I take it that you need to clean these package variables because you're sharing them with the Safe via share or share_from, and between runs in the compartment the values from the preceding run need to be wiped away. Is this principally to conserve memory/force garbage collection, or to prevent data from being improperly preserved between uses of the compartment? If the former, then I don't believe there's much you can do, as perl is reluctant to release memory back to the system. If the latter, then rather than this convoluted approach, why not simply maintain a list of shared variables, iterating over them, undef'ing each?

Re: better way to cleanup a package?
by Courage (Parson) on Dec 03, 2002 at 07:59 UTC
    To include a module again afresh you need to delete a key from %INC hash:
    delete $INC{Safe.pm};
    but IMHO this is not a "safe" way to use Safe.pm module.

    Best wishes,
    Courage, the Cowardly Dog

Re: better way to cleanup a package?
by adrianh (Chancellor) on Dec 04, 2002 at 12:21 UTC

    There's Symbol::delete_package available to clear a packages symbol table.

    This may not return you all the memory you think for various reasons:

    • it might be using XS code that doesn't free up the memory it claims
    • if there are references to things created by package they are not going to go away unless their reference count falls to zero... Are things sitting in a cache somewhere? Could there be circular references?

    There is also the fact that all of the perl implementations I've worked with do not return freed memory to the OS - so if that's what you're looking for I'm afraid you're out of luck.