{ # WRONG: my @queue = (); foreach (@_) { my ($a, $b, $ch) = /(\d*)[:]([^:])[:](.*?)$/; my %parent = (a => $a, b => $b); my @children = map { my ($d, $e, $f) = split /:/, $_; my %c = (d=>$d, e=>$e, f=>$f, p=>\%parent); \%c; } split /,/, $ch; $parent{children}=\@children; push @queue, \%parent; } while (pop @queue) { do_stuff($_); } # The item that was popped off the queue now is out of scope, # but its children point back to it, so it stays in memory. } # Now the whole queue is out of scope, but the items formerly # in it are still in memory, even now -- and there's no way # to get back to them and free them, because you've lost # track of all the references, even though they still exist. { # BETTER: my @queue = (); foreach (@_) { my ($a, $b, $ch) = /(\d*)[:]([^:])[:](.*?)$/; my %parent = (a => $a, b => $b); my @children = map { my ($d, $e, $f) = split /:/, $_; my %c = (d=>$d, e=>$e, f=>$f, p=>\%parent); \%c; } split /,/, $ch; $parent{children}=\@children; push @queue, \%parent; } while (pop @queue) { do_stuff($_); foreach (@{$$_{children}}) { $$_{p}=undef; # child no longer has reference to parent. } undef $_; # Now there are zero references to the item, # so it does go away, taking with it its # ch key and the anon array that is its # value, which drops the refcount to each # element of that array to zero, causing # them to be freed, which in turn frees # each of the children -- I think. } }