Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

phillup (4419)

phillup
  (email not shown publicly)
http://www.philsplace.org/

Journal of phillup (4419)

Friday November 12, 2004
12:48 PM

Garbage Collection Strangeness

[ #21827 ]

Here is a minimal script that demonstrates (on my system) the strange behavior I am experiencing.

If I uncomment the undef statement, then everything seems to work. But, if I let Perl take out the garbage it looks like my CGI::Session object gets destroyed before my own session object is destroyed. Even tho I still have a reference to the object. (Actually, my reference goes away!)

I can work around the problem by making sure I trigger the object destruction myself. But, I'd really like to know if the problem is in my mental picture of how things are supposed to work.

UPDATE: It appears to be my mental picture. ;-)

Apparently global garbage destruction is somewhat random in order. So, make sure you take out your own garbage if the order is important!

Any comments greatly appreciated!

-------

#! /usr/bin/perl
 
use strict;
use warnings;
 
my $session = new My::Session;
 
sub skipme{
  my $test = $session->{test}; # no I don't normally access the object data directly
                               # I just need to use the object in the sub to trigger
                               # the problem and I want to reduce the number of methods
                               # to the bare minimum to demonstrate the problem
} # sub skipme
 
print "\nDone\n";
#undef $session;
 
{#-----------------------------------------------------------------
 
  package My::Session;
 
  use strict;
  use warnings;
 
  my $session_dir = '/tmp/cgisession/';
  use CGI::Session::File;
 
  sub new{
    # get our class of object
    my $CLASS = shift;
 
    my $SELF = {};
 
    # get a new storage session
    $SELF->{session} = new CGI::Session("driver:File;serializer:FreezeThaw", undef, {Directory => $session_dir})
      || die 'Could not get new session store!';
 
    # and bless ourself
    bless $SELF, $CLASS;
 
    return $SELF;
  } # sub new
 
  sub DESTROY {
    my $SELF = shift;
 
    print "Hey!! Someone stole my session!\n" unless $SELF->{session};
  } # sub DESTROY
 
}#-----------------------------------------------------------------

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • You've got a closure there referencing $session inside skipme(). If you pass the object in instead, things will probably work as you expect.

    -Dom

    • Does this mean that Perl's garbage collection doesn't destroy objects based on a reference count?

      Or does the closure some how mess up the reference count?

      It seems to me that the $session instance has a reference to a CGI::Session object, so the CGI::Session object should not be destroyed until after the $session variable is.

      Or, do I have that wrong?

  • And global destruction's unordered, which is likely where your problem lies. When your program ends, perl just sweeps through all the oustanding live objects with destructors in pretty much a first-to-last order. (First to last in memory at least. This is not necessarily chronological order, nor will it necessarily be the same order from run to run of your program, depending on what its doing)

    The only safe way to handle things here is make sure that your objects die before global destruction.
    • So, in your example code, if you wrapped a block around everything from the "my $session = ..." to the "#undef ...", then the session would be closed properly when the block was exitted, but since you just "fall off the end" the remaining stuff gets discarded in arbitrary order. You would also have te same problem, I think, if you terminated with an explicit exit statement - so, as well as wrapping your mainline inside a block you could put a label (say EXIT:) on the block and change any exit statements an
    • Thanks for the response. What you describe is exactly what I have concluded is happening, I just didn't think it was supposed to happen that way.

      And global destruction's unordered, which is likely where your problem lies.

      Do you have a reference for this? I've looked and can't find a thing about it.

      I did find this in Programming Perl, 3rd Edition (page 331)

      When an interpreter shuts down, all its objects are destroyed, which is important for multithreaded or embedded Perl applications. Objects are alway

      • I found someone else mentioning [thepen.com]the fact that global destruction is unordered.
      • As I recall (from a long time ago), it is impossible to ensure a good ordering using just ref counts because it is easy to have reference loops (e.g. two objects each with a reference to the other or an object that has a reference to itself, or a list of things that links back to the "beginning" of the list). So, since most programs don't care about the order anyhow and the ones that do can arrange things for themselves, there was no point in spending any time to do a half-hearted ordering.