#!/usr/bin/env perl use warnings; use strict; # Debugging aids use Devel::Refcount 'refcount'; use Sub::Delete 'delete_sub'; { # This will act like a normal hash except it will print # "DESTROY" when it is destroyed (garbage collected). package DebugHash; BEGIN { require Tie::Hash; our @ISA = ('Tie::StdHash'); } sub DESTROY { print "DESTROY\n" } } { # Lexical scope for "my %hash". my %hash; # +1 reference to %hash (0+1=1) BEGIN { tie %hash, 'DebugHash' } # tie to debugging aid # Note: We'll use $hash{c} as a counter for debug output. # Apparently BEGIN{} blocks cause +1 reference to %hash (?) # Note: refcount()-1 since the argument \%hash is +1 reference. BEGIN { print ++$hash{c},": ",refcount(\%hash)-1,"\n" } # "1: 2" sub foo { # +1 reference to %hash (compile time) $hash{x}++; print ++$hash{c},": ",refcount(\%hash)-1,"\n"; } BEGIN { print ++$hash{c},": ",refcount(\%hash)-1,"\n" } # "2: 3" sub bar { # +1 reference to %hash (compile time) $hash{y}++; my $hashref = \%hash; # +1 reference to %hash (runtime) print ++$hash{c},": ",refcount(\%hash)-1,"\n"; } BEGIN { print ++$hash{c},": ",refcount(\%hash)-1,"\n" } # "3: 4" # Remember "BEGIN" is compile time, the following is run time. # The three references to %hash are the lexical "my %hash", # as well as "sub foo" and "sub bar". print ++$hash{c},": ",refcount(\%hash)-1,"\n"; # "4: 3" } # Lexical scope of "my %hash" ends, -1 reference to %hash. # The following calls are in "eval" b/c otherwise the calls # would be another reference keeping &main::foo/bar alive. eval "foo()"; # "5: 2" eval "bar()"; # "6: 3" delete_sub 'bar'; # -1 reference to %hash eval "foo()"; # "7: 1" delete_sub 'foo'; # -1 reference to %hash (1-1=0) => "DESTROY" print "Done.\n";