DekGenius.com
[ Team LiB ] Previous Section Next Section

4.3 Reference Counting and Nested Data Structures

The data remains alive until the last reference is destroyed, even if that reference is contained within a larger active data structure. Suppose an array element is itself a reference. Recall the example from Chapter 3:

my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
my @skipper_with_name = ("The Skipper", \@skipper);
my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
my @professor_with_name = ("The Professor", \@professor);
my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
my @gilligan_with_name = ("Gilligan", \@gilligan);
my @all_with_names = (
  \@skipper_with_name,
  \@professor_with_name,
  \@gilligan_with_name,
);

Imagine for a moment that the intermediate variables are all part of a subroutine:

my @all_with_names;

sub initialize_provisions_list {
  my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
  my @skipper_with_name = ("The Skipper", \@skipper);
  my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
  my @professor_with_name = ("The Professor", \@professor);
  my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
  my @gilligan_with_name = ("Gilligan", \@gilligan);
  @all_with_names = ( # set global
    \@skipper_with_name,
    \@professor_with_name,
    \@gilligan_with_name,
  );
}

initialize_provisions_list(  );

The value of @all_with_names is set to contain three references. Inside the subroutine are named arrays with references to arrays first placed into other named arrays. Eventually, the values end up in the global @all_with_names. However, as the subroutine returns, the names for the six arrays disappear. Each array has had one other reference taken to it, making the reference count temporarily two, and then back to one as the name is removed. Because the reference count is not yet zero, the data continues to live on, although it is now referenced only by elements of @all_with_names.

Rather than assign the global variable, you can rewrite this as:

sub get_provisions_list {
  my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
  my @skipper_with_name = ("The Skipper", \@skipper);
  my @professor = qw(sunscreen water_bottle slide_rule batteries radio);
  my @professor_with_name = ("The Professor", \@professor);
  my @gilligan = qw(red_shirt hat lucky_socks water_bottle);
  my @gilligan_with_name = ("Gilligan", \@gilligan);
  return (
    \@skipper_with_name,
    \@professor_with_name,
    \@gilligan_with_name,
  );
}

my @all_with_names = get_provisions_list(  );

Here, you create the value that will eventually be stored into @all_with_names as the last expression evaluated in the subroutine. A three-element list is returned and assigned. As long as the named arrays within the subroutine have had at least one reference taken of them, and it is still part of the return value, the data remains alive.[1]

[1] Compare this with having to return an array from a C function. Either a pointer to a static memory space must be returned, making the subroutine nonreentrant, or a new memory space must be malloc'ed, requiring the caller to know to free the data. Perl just does the right thing.

If the references in @all_with_names are altered or discarded, the reference count for the corresponding arrays is reduced. If that means the reference count has become zero (as in this example), those arrays themselves are also eliminated. Because these arrays also contain a reference (such as the reference to @skipper), that reference is also reduced by one. Again, that reduces the reference count to zero, freeing that memory as well, in a cascading effect.

Removing the top of a tree of data generally removes all the data contained within. The exception is when additional copies are made of the references of the nested data. For example, if you copied Gilligan's provisions:

my $gilligan_stuff = $all_with_names[2][1];

then when you remove @all_with_names, you still have one live reference to what was formerly @gilligan, and the data from there downward remains alive.

The bottom line is simply: Perl does the right thing. If you still have a reference to data, you still have the data.

    [ Team LiB ] Previous Section Next Section