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

I believe that I've stumbled across a problem with perl's garbage collector. I'm working with a set of nested objects/datastructures which (broken down to the ugly parts) can be described like this:

Let's start with a hash which contains all global configuration data, particularly the required database handler. This hash (let's call it %glob) is needed to bless a user-object and is furthermore a property of $user. It's all part of a website so CGI::Session becomes handy to control the user-session. As the user is needed in other parts of the programm the object is stored into %glob;

my $dbh = $glob{dbh}; my $session = new CGI::Session("driver:MySQL;id:MD5", $sid, { Handle = +> $dbh, LockHandler => $dbh }); my $user = bless ( { glob => \%glob, session => $session }, $class ); $glob{user} = $user;

Now I need an HTML Page.

my $page = bless ( { glob => \%glob }, $class );

So far, everything seems to work fine. The problem occurs when the script terminates. CGI::Session builds its data up on creation, manipulates it if required and writes the session into the database not until the DESTROY method of the session-object gets called. Unfortunately at this point the database handler is already destroyed and an error is yielded.

I've tried to narrow it down by writing DESTROY methods for both the page- and the user-object. The page gets destroyed first and with the page goes the database handler. A possible solution may be to destroy the user-object within the page's DESTROY method but then I'll had to consider that some pages may have subpages and remove the user-object from %glob before blessing a new page-object. (Actually I've already tried this - with the result that CGI::Session yields a slightly different error.)

From my point of view my problem seems to be that I disagree with perl's garbage collector on when to destroy my objects. Is there any way to tell him that I'd like to destroy the user-object first (including the session-object) and then the page-object?

[note]

Oh dear fellow monks, I can't even express my gratitude to this great site. By writing my problem down, trying to find the proper words to describe my problem, reflecting the different search-paths I've already tried and repeatedly thinking about the possible solutions, I've found a solution to my problem.

After the main function I'm calling the DESTROY method of the user-object which calls the appropriate method of the session-object to flush and destroy the session. As the page-object doesn't need any special treatment when it gets destroyed after the main script terminates, I don't care if the database handler is available then.

However, this leads me to another problem: should I delete my question or post it as part of contribution for other monks confronted with a similar problem as mine? I've chosen the latter but still remain to ask if there are other (better) solutions.

Thank you all for your advise.
slayven

--
trust in bash
but tie your camel

Replies are listed 'Best First'.
Re: destroying object
by Anomynous Monk (Scribe) on Mar 30, 2004 at 19:45 UTC
    Perl's garbage collector won't automatically get rid of structures with circular references until global destruction, at which point you don't know what the order will be. See "Two Phased Garbage Collection" in perldoc perlobj.

    The scope and desired lifetime of your different objects and variables isn't completely clear to me, but it looks to me like you could just add:

    use Scalar::Util 'weaken'; weaken $glob{user};
    after you set $glob{user}.
Re: destroying object
by dragonchild (Archbishop) on Mar 30, 2004 at 18:52 UTC
    Just a note: DESTROY functions aren't guaranteed to occur in any order. Not saying anything about your solution, just a comment in general.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

      Perl objects only get destroyed in the wrong order during 'global destruction'. If you avoid globals (enough to get your objects destroyed before 'global destruction' kicks in), then your objects get destroyed in a sensible order, always.

      I also consider this a bug in Perl, even though it has existed for a very long time.

      - tye