Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

Flyweight Objects and garbage collection

by BlaisePascal (Monk)
on Sep 04, 2000 at 20:17 UTC ( #31012=perlquestion: print w/replies, xml ) Need Help??

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

I was reading the excerpts of Damian Conway's OO Perl book that are on his website (while waiting for my paycheck to clear so I can order the book itself). Among lots of other useful things, he describes a technique for data encapsulation using flyweight objects:
package Foo; { my @foos; sub new { push @foos,{ name => $_[1] }; my $obj = $#foos; return bless \$obj, $_[0]; } sub getname { return $foos[${$_[0]}]->{name}; } }
His example was more useful than the "foo" class above, but this shows the basic idea. The actual objects are held in a dataspace lexically scoped to the package, and is inaccessible outside the package. Outside the package, all the rest of the world gets is a blessed handle to the data locked away in the package, and can't see anything to directly manipulate.

There does seem to be some limitations to this approach (such as difficulty doing inheritance, etc), but the one major question I have is with GC.

The actual objects are referred to by the array @foos, and only the array @foos. When the blessed handle goes out of scope, the object won't be cleaned up, because it is still being referred to by @foos. Only when the program exits will the object itself be cleaned. This could be a problem.

The obvious solution would be to add something like:

sub DESTROY { $foos[${$_[0]}] = undef; }
to the Foo class. Then, when the handle goes out of scope, Foo::DESTROY gets called, and all is well.

What I'm concerned about is cases where the handle gets copied before it goes out of scope:

sub usesfoo { my ($name,$population) = @_; my $foo = new Foo($name); my %ret = { name => $name, pop => $population, foo => $foo }; return \%ret; }
At the end of usesfoo, $foo falls out of scope. Is Perl smart enough to not call DESTROY $foo at that point, or will the copy of $foo saved in the return value be rendered useless?

Damian Conway's example does not include a destructor, so I can't tell by his example -- his looks to me like it leaks memory.

Replies are listed 'Best First'.
RE (tilly) 1: Flyweight Objects and garbage collection
by tilly (Archbishop) on Sep 04, 2000 at 20:24 UTC
    Yes, it leaks memory, yes, you could write a DESTROY like that, and internally Perl uses reference counting so that your destructor should not be called until all references are gone. (The current implementation will call it when the last reference goes. This deterministic behaviour may or may not survive. People like it and use it a lot, but there is constant grumbling about implementing real garbage collection some day.)
Re: Flyweight Objects and garbage collection
by chromatic (Archbishop) on Sep 04, 2000 at 20:29 UTC
    Perl implements its garbage collection with a reference counting implementation. Every variable has a reference count associated with it. When you create a new referent to that variable, the reference count increases.

    In usesfoo(), when you create a Foo object, you get $foo, with a reference count of one. (Yes, $foo is a referent.)

    When you put $foo in the %ret hash, all of a sudden $ret{foo} becomes a referent to that to which $foo points. (No dangling participle here.) Reference count++. That makes it two.

    At the end of the subroutine, after the return, the data structure we'll call %ret is still around because it gets returned. $foo is not so lucky, and goes out of scope. Reference count--. That makes it one. So whatever $foo pointed to is still around because what we call %ret in the subroutine still points to it.

    When you get rid of %ret, Perl will go through it all and decrease all the reference counts. Assuming that the rc for $foo is one at that point, it'll get garbage collected.

    Adding the DESTROY method to the flyweight class was a good idea. The memory leak you speak of would be in the block lexical @foos, if anywhere.

    Anyone in the know who's just stopped reeling from my simplification is welcome to jump in here and correct me.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://31012]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2020-04-04 00:30 GMT
Find Nodes?
    Voting Booth?
    The most amusing oxymoron is:

    Results (32 votes). Check out past polls.