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

I'm using a module that is very memory intensive. I'm also calling one of it's functions many times which construct a large amount of data. I would like to free the memory between each call so that my program can run with out running out of memory. I wrote the subroutine below but it doesn't completely free all of the memory. The program still runs out of memory. Can anyone see what else I need to do? The module I'm using is Spreadsheet::ParseExcel incase your wondering.
sub deleteref { my $ref = shift; foreach my $k (keys %$ref) { if (ref($ref->{$k}) eq 'SCALAR') { delete($ref->{$k}); } elsif (ref($ref->{$k}) eq 'HASH') { deleteref($ref->{$k}); } elsif (ref($ref->{$k}) eq 'ARRAY') { undef(@{$ref->{$k}}); } elsif (ref($ref->{$k}) eq 'CODE') { delete($ref->{$k}); } elsif (ref($ref->{$k}) eq 'REF') { deleteref($ref->{$k}); } elsif (ref($ref->{$k}) eq 'LVALUE') { delete($ref->{$k}); #} elsif (ref($ref->{$k}) eq '') { } else { delete($ref->{$k}); } } undef(%$ref); }

Replies are listed 'Best First'.
Re: recursive reference delete subroutine
by Zed_Lopez (Chaplain) on Dec 15, 2004 at 18:08 UTC
    undef $ref;

    should do it for you -- if its referent's reference count drops to zero, its memory will be freed automatically (and so on, recursively.)

    Keep in mind, the memory is only freed for reuse by your program, not to the OS, but that shouldn't be hurting you here.

    So my guesses would be that either you have a memory leak, or that you just plain don't have enough memory for your current algorithm with the data you're using, and you'll have to be cleverer about the algorithm -- no amount of undeffing or deleting is going to save you.

      I disagree; I think that answer merely hopes for a solution instead of answering the question directly.

      use Test::More tests => 2; sub undef_hash { my $ref = shift; undef $ref; } sub assign_hash { my $ref = shift; %$ref = (); } my $hash_one = { qw( foo bar baz quux ) }; undef_hash( $hash_one ); is( keys %$hash_one, 2, 'undef on hash reference should not clear it' ); my $hash_two = { qw( foo bar baz quux ) }; assign_hash( $hash_two ); is( keys %$hash_two, 0, 'assigning empty list to hash reference should clear it' );

      Update: Ahh, I misunderstood. Yes, replacing the subcall will probably work.

        I was presuming the OP would replace the calls to deleteref with just the undef. You're right, of course, that making a copy of the reference in a subroutine and undeffing that is a no-op.

        use Test::More tests => 2; sub deleteref { my $h = shift; undef $h; } my $c = {d => 3}; deleteref($c); is( keys %$c, 1, 'undef on copy of hashref in a subroutine should not clear it' ); undef $c; is( keys %$c, 0, 'undef on hash reference, not a copy of it in a subroutine, should + clear it' );