Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Is there a penalty for namespace use?

by zentara (Archbishop)
on Dec 29, 2004 at 16:14 UTC ( #418089=perlquestion: print w/replies, xml ) Need Help??

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

I've been toying around with modules, and with Tk I know you need to reuse a module's object's namespace, or you get a memory gain. So I decided to try and simplify it to it's simplest form, to see what is going on. So in the examples below, if I use a straight hash to store data, I can load, empty, and reuse the hash with no memory gain on the second load.

With a module however, no matter what I do, the "new" causes quite a memory gain on the second use, even if I try to load the objects into a reusable hash. So, I'm sure this is a common question, but is there a way to completely return a destroyed objects memory, so it can be reused? Or is there just an unavoidable penalty for creating a new namespace?

#this is a pure hash, and it works as I expect #!/usr/bin/perl use warnings; use strict; my %bubs; for(1.. 500){ $bubs{$_}{'stuff'} = [1..1000]; print "adding $_\n"; } <>; for(1.. 500){ $bubs{$_}=(); delete $bubs{$_}; print "deleting $_\n"; } <>; for(1.. 500){ $bubs{$_}{'stuff'} = [1..1000]; print "adding $_\n"; } for(1.. 500){ $bubs{$_}=(); delete $bubs{$_}; print "deleting $_\n"; } <>; __END__ #################################### # this is with objects, where it dosn't # reuse a DESTROYED objects space even though I # stuff them into the same hash space #!/usr/bin/perl use warnings; use strict; my %bubs; for(1.. 500){ $bubs{$_} = ZtkBubject->new( -name => $_, ); $bubs{$_}->DESTROY; delete $bubs{$_}; $bubs{$_}=(); } <>; for(1.. 500){ $bubs{$_} = ZtkBubject->new( -name => $_, ); $bubs{$_}->DESTROY; } <>; #===================================================================== +======== # ZtkBubject Class #===================================================================== +======== package ZtkBubject; use strict 'vars'; use Carp; sub new { my ($class, %arg) = @_; # object attributes my $self = { 'name' => $arg{-name}, #identifying name }; bless $self; # print "just blessed $self\n"; $self->{self} = $self; $self->{stuff} = [1..1000]; #add some memory usage return $self; } ############################################# sub DESTROY{ my ($self) = @_; print "destroying->", $self->{name},' ',$self,"\n"; } ########################################### 1; __END__


I'm not really a human, but I play one on earth. flash japh

2004-12-29 Janitored by Arunbear - added readmore tags, as per Monastery guidelines

Replies are listed 'Best First'.
Re: Is there a penalty for namespace use?
by dave_the_m (Monsignor) on Dec 29, 2004 at 17:38 UTC
    $self->{self} = $self;
    You are creating a reference loop which stops the objects being freed. Note also that it's unusual to explicitly call DESTROY()

    Dave.

      Not only is it unusual, it is incorrect. Perl itself will call DESTROY for you when it is about to lose its last reference to an object. You should never call the DESTROY method yourself because the object *isn't* being destroyed when you call the function.
Re: Is there a penalty for namespace use?
by osunderdog (Deacon) on Dec 29, 2004 at 18:34 UTC
Re: Is there a penalty for namespace use?
by revdiablo (Prior) on Dec 29, 2004 at 18:09 UTC

    As dave_the_m pointed out, putting a copy of $self as an attribute in $self is going to prevent it from being garbage collected. But I have to wonder what the point of doing so is, anyway? The reference to $self is stored in... $self. So to get to $self, you first need to get to... $self. It doesn't make a whole lot of sense. :-)

Re: Is there a penalty for namespace use?
by zentara (Archbishop) on Dec 30, 2004 at 07:47 UTC
    Never mind... I found the answer by playing with it. It seems you have to loop thru it a few times for the memory to settle down to a constant value, and since I was using 2 hashes, Perl let it double. However, the following does reclaim memory like I would expect.
    #!/usr/bin/perl use warnings; use strict; my %bubs; while(1){ for(1.. 500){ $bubs{$_} = ZtkBubject->new( -name => $_, ); $bubs{$_}=(); delete $bubs{$_}; } %bubs = (); undef %bubs; print "\nCheck memory now and hit enter\n"; <>; } #===================================================================== +======== # ZtkBubject Class #===================================================================== +======== package ZtkBubject; use strict 'vars'; use Carp; sub new { my ($class, %arg) = @_; my $self = { 'name' => $arg{-name}, }; bless $self; # print "just blessed $self\n"; $self->{stuff} = [1..1000]; #add some memory usage return $self; } ############################################# sub DESTROY{ my ($self) = @_; print "destroying->", $self->{name},' ',$self,"\n"; } ########################################### 1;

    I'm not really a human, but I play one on earth. flash japh
Re: Is there a penalty for namespace use?
by zentara (Archbishop) on Dec 30, 2004 at 06:48 UTC
    Oops I goofed with the $self->{self}= $self; I was just experimenting around with storing the object's name in it's own namespace, and stupidly left that in there. Circular reference is now imprinted in my memory.

    But even if I remove it, and not call DESTROY myself, and take all references to the objects out of scope, the memory is not reused. So can anyone show how to prevent the memory doubling in the following? I use 2 different hashes, and undef the first, so why isn't the memory available for the second hash to reuse? I would guess that it is somehow not releasing the array's used in $self->{stuff}, but if I put @{$self->{stuff}} = () in the DESTROY sub, it dosn't clear it.

    #!/usr/bin/perl use warnings; use strict; my %bubs; my %bubs1; for(1.. 500){ $bubs{$_} = ZtkBubject->new( -name => $_, ); $bubs{$_}=(); delete $bubs{$_}; $bubs{$_}=(); } %bubs = (); undef %bubs; print "Check memory now and hit enter\n"; <>; for(1.. 500){ $bubs1{$_} = ZtkBubject->new( -name => $_, ); } print "Check memory now and hit enter, its doubled\n"; <>; #===================================================================== +======== # ZtkBubject Class #===================================================================== +======== package ZtkBubject; use strict 'vars'; use Carp; sub new { my ($class, %arg) = @_; my $self = { 'name' => $arg{-name}, }; bless $self; # print "just blessed $self\n"; $self->{stuff} = [1..1000]; #add some memory usage return $self; } ############################################# sub DESTROY{ my ($self) = @_; @{$self->{stuff}} = (); print "destroying->", $self->{name},' ',$self,"\n"; } ########################################### 1;

    I'm not really a human, but I play one on earth. flash japh
Re: Is there a penalty for namespace use?
by jbrugger (Parson) on Dec 30, 2004 at 01:39 UTC
    But whenever you NEED circular references, be sure to use
    use Scalar::Util qw(weaken);
    and:
    weaken( $self->{parent} = $parent );
    so there is no reference count, and as soon the parent object is destroyed, the child is cleaned up by the garbage collector.

      Er, i hate to say this but i dont think thats a great idea unless you have seriously good reasons.

      The way to do this is to make sure the reference that is blessed is not part of the cyclic structure. Consider the following code:

      use strict; use warnings; sub MyBinTree::insert { my ($self,$string,$node)=@_; my $ins_ref; unless ($node) { unless ($self->{root}) { $ins_ref=\$self->{root} } else { $node=$self->{root}; } } unless ($ins_ref) { if ($string lt $node->{val}) { if ($node->{left}) { return $self->insert($string,$node->{left}) } else { $ins_ref=\$node->{left}; } } elsif ($string gt $node->{val}) { if ($node->{right}) { return $self->insert($string,$node->{right}) } else { $ins_ref=\$node->{right}; } } else { return $node; } } $$ins_ref={val=>$string,parent=>$node}; return $$ins_ref } sub MyBinTree::new { my ($class)=@_; my $self= bless { },$class; print "Created new $self\n"; return $self; } sub MyBinTree::_traverse { my ($self,$node,$sub)=@_; if ($node->{left}) { $self->_traverse($node->{left},$sub); } { local $_=$node; $sub->(); } if ($node->{right}) { $self->_traverse($node->{right},$sub); } } sub MyBinTree::traverse { my ($self,$sub)=@_; $self->_traverse($self->{root},$sub) if $self->{root}; } sub MyBinTree::DESTROY { my $self=shift; print "Destroying new $self\n"; $self->traverse(sub { delete $_->{parent} }); print "Destroyed\n"; } { my $container=MyBinTree->new(); $container->insert($_) for (my @words=qw(foo bar baz bop fop cool)); $container->traverse(sub { print $_->{val},"\n" }); print "Exiting scope.\n"; }

      Which outputs:

      Created new MyBinTree=HASH(0x1acef24) bar baz bop cool foo fop Exiting scope. Destroying new MyBinTree=HASH(0x1acef24) Destroyed

      The internal data structure is entirely self referential and cyclic. Yet it destroys just fine, and with no weakref.

      ---
      demerphq

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://418089]
Approved by Arunbear
Front-paged by Courage
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2019-11-13 07:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Strict and warnings: which comes first?



    Results (69 votes). Check out past polls.

    Notices?