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

Hi everyone, I'm creating a script that build node tree (using HASH ref) After i've done using the tree, i want to deallocate the nodes. should i traverse through all the nodes and use
sub deletenode { $node = shift; if ($node->{'child'}) { foreach ($node->{'child'}) { deletenode($_); } } else { $node = {}; } }
or simply delete the tree (assume all the nodes are automatically recovered)?
$tree = {};
thanks in advance :)

Replies are listed 'Best First'.
Re: Deallocating HASH pointer
by bsb (Priest) on May 11, 2004 at 09:20 UTC
    You only need to worry about memory if you have a circular reference (say a "parent" link).
    $tree = undef;
    might be better. You'll get a warning later if you try to use it.

    See WeakRef and Data::Structure::Util's has_circular_ref

      You'll get a warning later if you try to use it.
      Not necessarily:
      #line 1 use strict; use warnings; our $tree; $tree = {}; $$tree{autov} = "ivify"; warn %$tree; # vs. $tree = undef; $$tree{autov} = "ivify"; warn %$tree;
      you might even want to do:
      undef $tree
      this will remove the complete $tree variable from your scope, not just 'undef' it.
Re: Deallocating HASH pointer
by hv (Prior) on May 11, 2004 at 09:49 UTC

    For a tree, you should be fine deleting the top node (or simply letting the variable holding it go out of scope).

    Since perl5 uses reference counting to know when to free the space used by variables, this strategy works fine except when you have a data structure with circular references - for example when modelling a graph, or a tree in which each node also holds a reference to the top of the tree.

    In such cases extra care is needed: you can either avoid circularity using weak references, or take care to clean up enough of the references by hand to allow perl to do the rest.

    Hugo

      What about if the '$tree' is a static variable?
      BEGIN { $tree = {}; sub createTree { # we create big tree ... } sub deleteTree { $tree = undef; # or $tree = {}; } } createTree(); deleteTree();
      Is this also apply?
Re: Deallocating HASH pointer
by ysth (Canon) on May 11, 2004 at 09:22 UTC
    Just delete the tree, unless you have circular references (e.g. child nodes have a reference to the parent).
Re: Deallocating HASH pointer
by mirod (Canon) on May 11, 2004 at 10:08 UTC

    It depends whether you nodes have cycles or not. If the parent points to the children but the children don't point back to the parent, nor to each other, then deleting the tree will delete all the nodes. Otherwise they will not, as even if you drop the reference to the root, its children will still point at it, hence its refcount (the number of variables that point at the root) will not go down to 0 and it will not be freed.

    The 2 ways to solve the problem are: to manually go through the descendants of the root, as you shown in your post, or to use weaken, from Scalar::Util: weaken all references to a node except one (typically the link from the parent), and when the root is deleted the refcount of its children _will_ go down to 0, and so on for all nodes in the tree.