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

Hello Monks,
What happens to references when you "delete" them?
Consider this example:
my $array_ref = []; for(1 ... 10) { my $hash_ref = { foo => foo, bar => bar }; push(@{$array_ref}, $hash_ref); } $array_ref = [];
$array_ref does actually is an empty array reference but what happens to all the hash_refs? would I need to loop through the hash ref and actually set all the hash refs to {} to truly delete this array ref?

Also if those hash refs contained array refs of hash refs themselves would i need to recurse thru the whole tree and delete them that way? My question is what is the easiest way to delete references without causing a memory leak.

My concern is a persistent script using mod_perl or a daemon of some sort, experience problems if these stayed in memory without getting cleaned up.

Should I just not use references and actually use "real" array's and hashes so I can ensure that memory leaks do not happen? Sorry about the long winded post.

Replies are listed 'Best First'.
Re: deleteing references
by kyle (Abbot) on Jun 09, 2008 at 02:48 UTC

    In your example, the hash references and the original array reference are all freed when when the last line is executed. If any part of the structure contained objects, that's when their DESTROY methods would be called.

    Perl uses reference counting to determine when to free memory, so you mostly don't have to worry about it unless you've created a circular reference. For example:

    my $ar = []; push @{$ar}, $ar; # $ar can only be destroyed manually.

    In that case, you'd have to walk around your structure and undef the relevant references manually. Another way to handle this is with weaken in Scalar::Util. weaken makes a reference "weak" so that it doesn't count toward the reference count. With that, you can make your circular references weak, and destruction will happen normally. Note that a copy of a weak reference is not weak.

    use Scalar::Util qw( weaken is_weak ); my $ar = []; push @{ $ar }, weaken $ar; # $ar will be destroyed normally. if ( is_weak $ar->[0] ) { print "First list item is weak\n"; } my $copy = $ar->[0]; if ( ! is_weak $copy ) { print "copy is not weak\n"; }

    Finally, you asked about real memory being freed in a mod_perl environment. When perl releases some data structure, it doesn't necessarily return that memory to the OS. It will keep it and use it again when another data structure wants it.

Re: deleteing references
by pc88mxer (Vicar) on Jun 09, 2008 at 02:44 UTC
    Unreferenced structures are automatically reclaimed by perl. The term for this is "garbage collected". Internally, perl keeps track of how many references an object has. When that count drops to zero, perl reclaims the memory the object used.

    The system isn't perfect. For instance, circular references can confuse perl, but for the most part it works well enough.

    Some relevant pm articles on the subject: Re: undefining hashes to free memory

Re: deleteing references
by ikegami (Patriarch) on Jun 09, 2008 at 06:52 UTC

    [] creates a new empty array and returns a reference to it.

    If your goal was simply to empty the array, you could use @$array_ref = ();

    If your goal was to free the array and the reference, you could use undef $array_ref; or let the reference fall out of scope.

    { my $array_ref = []; for(1 ... 10) { my $hash_ref = { foo => foo, bar => bar }; push(@{$array_ref}, $hash_ref); } } # $array_ref is freed here.
Re: deleteing references
by CountZero (Bishop) on Jun 09, 2008 at 05:18 UTC
    But of course, if you have a variable referencing one of these internal hash-refs then the garbage collector cannot free that memory. How much of the overlying variable structure remains alive, I cannot guess. Other Monks, more conversant with Perl's internals might be able to help you.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      You mean like

      my $array_ref = []; for(1 .. 2) { my $hash_ref = { foo => foo, bar => bar }; push(@{$array_ref}, $hash_ref); } my $hash_ref = $array_ref->[0]; $array_ref = [];

      You'll be left with the hash ref, the referenced hash, it's keys and values.

      Here's what happens, illustrated!

      Initial State: $array_ref $hash_ref +--------------+ +--------------+ | array ref | | hash ref | +--------------+ +--------------+ | refcount = 1 | | refcount = 1 | +--------------+ +--------------------+ +--------------+ | o=====> | array | | o | +--------------+ +--------------------+ +---------- : -+ | refcount = 1 | : +--------------------+ : | element 0 | : | +--------------+ | : | | hash ref | | : | +--------------+ | : | | refcount = 1 | | V | +--------------+ | +--------------+ | | o========> | hash | | +--------------+ | +--------------+ +--------------------+ | refcount = 2 | | element 1 | +--------------+ | +--------------+ | | keys & vals | | | hash ref | | +--------------+ | +--------------+ | | | refcount = 1 | | | +--------------+ | +--------------+ | | o========> | hash | | +--------------+ | +--------------+ +--------------------+ | refcount = 1 | +--------------+ | keys & vals | +--------------+ ##### After the array reference is overwritten: +--------------+ +--------------+ | array ref | | hash ref | +--------------+ +--------------+ | refcount = 1 | | refcount = 1 | +--------------+ +--------------------+ +--------------+ | o | | array | | o | +---------- : -+ +--------------------+ +---------- : -+ : | refcount = 0 | : : +--------------------+ : V | element 0 | : +--------------+ | +--------------+ | : | array | | | hash ref | | : +--------------+ | +--------------+ | : | refcount = 1 | | | refcount = 1 | | V +--------------+ | +--------------+ | +--------------+ | no elements | | | o========> | hash | +--------------+ | +--------------+ | +--------------+ +--------------------+ | refcount = 2 | | element 1 | +--------------+ | +--------------+ | | keys & vals | | | hash ref | | +--------------+ | +--------------+ | | | refcount = 1 | | | +--------------+ | +--------------+ | | o========> | hash | | +--------------+ | +--------------+ +--------------------+ | refcount = 1 | +--------------+ | keys & vals | +--------------+ ##### Automatically, the original array is freed since its refcount == 0. +--------------+ +--------------+ | array ref | | hash ref | +--------------+ +--------------+ | refcount = 1 | | refcount = 1 | +--------------+ +--------------+ | o | | o | +---------- : -+ +---------- : -+ : : : : V : +--------------+ +--------------+ : | array | | hash ref | : +--------------+ +--------------+ : | refcount = 1 | | refcount = 0 | V +--------------+ +--------------+ +--------------+ | no elements | | o========> | hash | +--------------+ +--------------+ +--------------+ | refcount = 2 | +--------------+ +--------------+ | keys & vals | | hash ref | +--------------+ +--------------+ | refcount = 0 | +--------------+ +--------------+ | o========> | hash | +--------------+ +--------------+ | refcount = 1 | +--------------+ | keys & vals | +--------------+ ##### Automatically, the hash refs with refcount == 0 are freed. +--------------+ +--------------+ | array ref | | hash ref | +--------------+ +--------------+ | refcount = 1 | | refcount = 1 | +--------------+ +--------------+ | o | | o | +---------- : -+ +---------- : -+ : : : : V : +--------------+ : | array | : +--------------+ : | refcount = 1 | V +--------------+ +--------------+ | no elements | | hash | +--------------+ +--------------+ | refcount = 1 | +--------------+ | keys & vals | +--------------+ +--------------+ | hash | +--------------+ | refcount = 0 | +--------------+ | keys & vals | +--------------+ ##### Automatically, the hash with refcount == 0 is freed. +--------------+ +--------------+ | array ref | | hash ref | +--------------+ +--------------+ | refcount = 1 | | refcount = 1 | +--------------+ +--------------+ | o | | o | +---------- : -+ +---------- : -+ : : : : V : +--------------+ : | array | : +--------------+ : | refcount = 1 | V +--------------+ +--------------+ | no elements | | hash | +--------------+ +--------------+ | refcount = 1 | +--------------+ | keys & vals | +--------------+
        Thanks for your replies guys... It's been of much help :]