Singleton and garbage collection

Discussion in 'Perl Misc' started by Ivan Fomichev, Mar 8, 2006.

  1. Hi, folks,

    I've encountered a garbage collection problem. It seems, that perl
    destroys an object in spite of an existing reference. I'm using perl
    v5.8.4. Here is a piece of code:

    use strict;
    package Singleton;
    use Data::Dumper;
    my $self;
    sub new {
    print +(caller(0))[3], "\n";
    my ($class) = shift;
    return $self if $self;

    my $item = Item->new();
    $self = bless \$item => $class;
    print Dumper($self);
    return $self;
    }
    sub DESTROY {
    print +(caller(0))[3], "\n";
    print Dumper(shift);
    }
    package Item;
    sub new {
    print +(caller(0))[3], "\n";
    return bless \(my $self = "value") => shift;
    }
    sub DESTROY {
    print +(caller(0))[3], "\n";
    }
    package main;
    my $s = Singleton->new();
    __END__

    Output is:

    Singleton::new
    Item::new
    $VAR1 = bless( do{\(my $o = bless( do{\(my $o = 'value')}, 'Item' ))},
    'Singleton' );
    Item::DESTROY
    Singleton::DESTROY
    $VAR1 = bless( do{\(my $o = undef)}, 'Singleton' );

    Where is the problem? There is no circular references of whatever, so
    why does perl do, what it does? Is it a bug? Is there any workaround?
    Do you have any ideas?

    If it were not a singleton, everything worked fine, but a singleton is
    the very thing I need.

    use strict;
    package Object;
    use Data::Dumper;
    sub new {
    print +(caller(0))[3], "\n";
    my ($class) = shift;

    my $item = Item->new();
    my $self = bless \$item => $class;
    print Dumper($self);
    return $self;
    }
    sub DESTROY {
    print +(caller(0))[3], "\n";
    print Dumper(shift);
    }
    package Item;
    sub new {
    print +(caller(0))[3], "\n";
    return bless \(my $self = "value") => shift;
    }
    sub DESTROY {
    print +(caller(0))[3], "\n";
    }
    package main;
    my $o = Object->new();
    __END__

    And here is a reasonable output:

    Object::new
    Item::new
    $VAR1 = bless( do{\(my $o = bless( do{\(my $o = 'value')}, 'Item' ))},
    'Object' );
    Object::DESTROY
    $VAR1 = bless( do{\(my $o = bless( do{\(my $o = 'value')}, 'Item' ))},
    'Object' );
    Item::DESTROY

    --
    With best regards,
    Ivan
    Ivan Fomichev, Mar 8, 2006
    #1
    1. Advertising

  2. Ivan Fomichev

    Guest

    Ivan Fomichev wrote:
    >
    > I've encountered a garbage collection problem. It seems, that perl
    > destroys an object in spite of an existing reference.
    >
    > Where is the problem? There is no circular references of whatever, so
    > why does perl do, what it does? Is it a bug? Is there any workaround?
    > Do you have any ideas?



    For one thing, even a singleton gets destroyed when a program ends
    (why shouldn't it?). To explain a little better, try inserting this
    line of code as the last line of your singleton script (right after you
    declare $s and right before the __END__ tag):

    my $s2 = Singleton->new();

    Now run the program. You'll notice that Singleton::DESTROY() only
    gets called once, despite the fact that Singleton->new() got called
    twice. In other words, only one object of the Singleton class was
    created, so only one was DESTROY()ed.

    Try adding this similar line:

    my $o2 = Object->new();

    to the end of your second program (the one that doesn't use singletons)
    and you'll see that Object::DESTROY() gets called twice.

    I think your mistake was in thinking that singletons never get
    destroyed. They do -- but generally when programs terminate. It's
    just that singletons still maintain the right to get destroyed once.

    I hope this clears things up, Ivan.

    -- Jean-Luc Romano
    , Mar 8, 2006
    #2
    1. Advertising

  3. Hello, Jean-Luc,

    It's not a secret for me, that singletons are destroyed like any other
    objects. The problem I reported was that an Item instance is destroyed
    before a Singleton instance, which contains a reference to it.

    Sorry for an inaccurate question.

    --
    With best regards,
    Ivan
    Ivan Fomichev, Mar 8, 2006
    #3
  4. Ivan Fomichev

    Guest

    Ivan Fomichev wrote:
    >
    > It's not a secret for me, that singletons are destroyed like any other
    > objects. The problem I reported was that an Item instance is destroyed
    > before a Singleton instance, which contains a reference to it.



    Er... it's possible I don't understand your question. Shouldn't any
    and all objects contained in the Singleton class be destroyed before
    the Singleton class itself gets destroyed (just like any other object)?

    Looking at your output:

    Item::DESTROY
    Singleton::DESTROY

    This shows that the Item object gets destroyed first (before the
    Singleton object). I don't see why this is a problem, partly because
    the Item object isn't a Singleton object (unlike the Singleton
    package). In other words, there's nothing stopping you from having
    more than Item instantiation.

    And if I still don't understand your problem, I hope you can figure
    out what's going on anyway.

    Good luck!

    -- Jean-Luc
    , Mar 8, 2006
    #4
  5. Ivan Fomichev

    Guest

    "Ivan Fomichev" <> wrote:
    > Hello, Jean-Luc,
    >
    > It's not a secret for me, that singletons are destroyed like any other
    > objects. The problem I reported was that an Item instance is destroyed
    > before a Singleton instance, which contains a reference to it.
    >
    > Sorry for an inaccurate question.


    During global destruction, objects are destroyed in whatever order perl
    feels like.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Mar 8, 2006
    #5
  6. Ivan Fomichev

    Anno Siegel Guest

    <> wrote in comp.lang.perl.misc:
    > "Ivan Fomichev" <> wrote:
    > > Hello, Jean-Luc,
    > >
    > > It's not a secret for me, that singletons are destroyed like any other
    > > objects. The problem I reported was that an Item instance is destroyed
    > > before a Singleton instance, which contains a reference to it.
    > >
    > > Sorry for an inaccurate question.

    >
    > During global destruction, objects are destroyed in whatever order perl
    > feels like.


    Indeed. It's *supposed* to break (circular) references in that stage.

    This is really another object lesson on the subject "Write Robust
    Destructors". Don't ever assume anything, you'll get called in the
    weirdest situations.

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
    Anno Siegel, Mar 8, 2006
    #6
  7. Anno Siegel wrote:
    > > During global destruction, objects are destroyed in whatever order perl
    > > feels like.

    > Indeed. It's *supposed* to break (circular) references in that stage.


    Everything's fine, but there are no circular references here, as far as
    I understand my code. So I suppose, that they should be garbage
    collected during reference-based garbage collection phase, not during
    mark-and-sweep phase. So I expect, that Item should not be garbage
    collected before Singleton, since the second keeps a reference to the
    former. Please refer to perlobj. Am I wrong? Please disappoint me.

    --
    With best regards,
    Ivan
    Ivan Fomichev, Mar 9, 2006
    #7
  8. "Ivan Fomichev" <> wrote in
    news::

    > Anno Siegel wrote:
    >> > During global destruction, objects are destroyed in whatever order
    >> > perl feels like.

    >> Indeed. It's *supposed* to break (circular) references in that
    >> stage.

    >
    > Everything's fine, but there are no circular references here, as far
    > as I understand my code. So I suppose, that they should be garbage
    > collected during reference-based garbage collection phase, not during
    > mark-and-sweep phase. So I expect, that Item should not be garbage
    > collected before Singleton, since the second keeps a reference to the
    > former. Please refer to perlobj. Am I wrong? Please disappoint me.


    I am not expert, but it makes sense to me that objects are destroyed in
    the order they were created.

    At program end, cleaning up Singleton means also cleaning up everything
    to which it holds a reference. Note that this is my interpretation based
    on observed behavior, rather than any first hand knowledge of how
    garbage collection works.

    Sinan
    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Mar 9, 2006
    #8
  9. A. Sinan Unur wrote:
    > I am not expert, but it makes sense to me that objects are destroyed in
    > the order they were created.

    That is not true. For an easy disproof, please see sample code with
    Object class above.

    > At program end, cleaning up Singleton means also cleaning up everything
    > to which it holds a reference.

    Sure, but destructor for Item should be called *after* destructor for
    Singleton. Item instance should not be destroyed, as long as I keep a
    reference to it, because I may want to access Item data from Singleton
    destructor (and that's the very thing I want).

    --
    With best regards,
    Ivan
    Ivan Fomichev, Mar 9, 2006
    #9
  10. Ivan Fomichev

    Anno Siegel Guest

    Ivan Fomichev <> wrote in comp.lang.perl.misc:
    > Anno Siegel wrote:
    > > > During global destruction, objects are destroyed in whatever order perl
    > > > feels like.

    > > Indeed. It's *supposed* to break (circular) references in that stage.

    >
    > Everything's fine, but there are no circular references here, as far as
    > I understand my code.


    It doesn't matter if there are, in fact, circular references. You just
    can't expect global destruction to respect existing references.

    > So I suppose, that they should be garbage
    > collected during reference-based garbage collection phase, not during
    > mark-and-sweep phase.


    No, that's the difference (one of them) between the singleton scenario
    and the standard class setup. With the singleton, the first thing
    ->new returns is stored in a global lexical. So it *must* remain until
    global destruction.

    I have appended a setup, similar to your non-singleton example. The
    first few lines is where the action is. They are

    # my $global;
    # sub access_global { $global }
    {
    my $obj = Object->new;
    # $global = $obj;
    }
    print "bare-block destruction done, global destruction begins\n";
    exit;

    If you run it as is, $obj and then its depending Item object are destroyed
    when the bare block ends, before global destruction.

    After activating the first and fifth lines, assigning $obj to a global
    variable, $obj survives the block and is destroyed globally, but (on
    my machine, with my perl) the sequence of operation is the same: First
    $obj dies, then the anonymous Item object.

    If you also have a sub that accesses the global variable, things change.
    After activation of the second line, the sequence of destruction reverses
    and Item is destroyed first, at least that's what I see on two machines.
    I don't claim to understand why this is so, and it doesn't really matter.
    Global destruction happens essentially at random.

    Your singleton-scenario is close to the situation we have here: There
    is a global variable that holds the reference, and that variable is
    accessed by a sub (->new itself, in that case). Apparently you got
    the same behavior. There is nothing wrong with that.

    The lesson is, don't assume a particular sequence in object destruction.
    In fact, in a destructor it's best not to assume anything.

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
    Anno Siegel, Mar 9, 2006
    #10
  11. Ivan Fomichev

    Anno Siegel Guest

    Anno Siegel <-berlin.de> wrote in comp.lang.perl.misc:
    > Ivan Fomichev <> wrote in comp.lang.perl.misc:
    > > Anno Siegel wrote:


    > I have appended a setup, similar to your non-singleton example. The


    Sorry, forgot to append the complete program. Here is is:


    #!/usr/bin/perl
    use strict; use warnings; $| = 1; # @^~`
    use Vi::QuickFix;

    my $global;
    # sub access_global { $global }
    {
    my $obj = Object->new;
    $global = $obj;
    }
    print "bare-block destruction done, global destruction begins\n";
    exit;


    package Object;

    sub new {
    Aux::show_sub();
    my $class = shift;
    my $item = Item->new( 'woohoo');
    bless \ $item, $class;
    }

    sub DESTROY {
    Aux::show_sub();
    }

    package Item;

    sub new {
    Aux::show_sub();
    my ( $class, $val) = @_;
    bless \ $val, $class;
    }


    sub DESTROY {
    Aux::show_sub();
    }

    package Aux;

    sub show_sub { print +( caller( 1))[ 3], "\n" }
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
    Anno Siegel, Mar 9, 2006
    #11
  12. "Ivan Fomichev" <> wrote in
    news::

    > A. Sinan Unur wrote:
    >> I am not expert, but it makes sense to me that objects are destroyed
    >> in the order they were created.

    > That is not true. For an easy disproof, please see sample code with
    > Object class above.


    I had meant in the reverse order they were created. Like popping
    elements from a stack.

    >> At program end, cleaning up Singleton means also cleaning up
    >> everything to which it holds a reference.

    > Sure, but destructor for Item should be called *after* destructor for
    > Singleton. Item instance should not be destroyed, as long as I keep a
    > reference to it, because I may want to access Item data from Singleton
    > destructor (and that's the very thing I want).


    During program execution time, yes. I just don't see why that should
    hold when the program terminates. I don't think there is a language that
    makes guarantee regarding regarding the order of object destruction
    during program termination.

    > --
    > With best regards,


    My newsreader automatically snips signatures if you use a proper sig
    separator. That is, you need 'dash-dash-space-newline' before your sig.

    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Mar 9, 2006
    #12
  13. Anno Siegel wrote:
    > The lesson is, don't assume a particular sequence in object destruction.
    > In fact, in a destructor it's best not to assume anything.


    Thank you very much for a detailed answer, things got much clearer now.

    --
    With best regards,
    Ivan
    Ivan Fomichev, Mar 9, 2006
    #13
  14. I'm glad to inform, that I've found a satisfactory workaround. END can
    be used instead of DESTROY. Though I am not sure, if there can be side
    effects of such use.

    use strict;
    package Singleton;
    use Data::Dumper;
    my $self;
    sub new {
    print +(caller(0))[3], "\n";
    my ($class) = shift;
    return $self if $self;

    my $item = Item->new();
    $self = bless \$item => $class;
    print Dumper($self);
    return $self;
    }

    sub END {
    print +(caller(0))[3], "\n";
    print Dumper($self);
    }

    package Item;
    sub new {
    print +(caller(0))[3], "\n";
    return bless \(my $self = "value") => shift;
    }

    sub DESTROY {
    print +(caller(0))[3], "\n";
    }

    package main;
    my $s = Singleton->new();
    __END__

    Output:

    Singleton::new
    Item::new
    $VAR1 = bless( do{\(my $o = bless( do{\(my $o = 'value')}, 'Item' ))},
    'Singleton' );
    Singleton::END
    $VAR1 = bless( do{\(my $o = bless( do{\(my $o = 'value')}, 'Item' ))},
    'Singleton' );
    Item::DESTROY

    --
    With best regards,
    Ivan
    Ivan Fomichev, Mar 9, 2006
    #14
  15. Ivan Fomichev

    Guest

    "Ivan Fomichev" <> wrote:
    > Anno Siegel wrote:
    > > > During global destruction, objects are destroyed in whatever order
    > > > perl feels like.

    > > Indeed. It's *supposed* to break (circular) references in that stage.

    >
    > Everything's fine, but there are no circular references here, as far as
    > I understand my code.


    True, but perl wants to be ready for that event, whether it actually
    happens to occur in your particular code or not.

    > So I suppose, that they should be garbage
    > collected during reference-based garbage collection phase, not during
    > mark-and-sweep phase.


    The lexical variable $self doesn't seem to go away until the mark and sweep
    phase, therefore the reference-chain it holds survive until after
    reference- based phase is done.

    If you add a finalize method to the singleton which does an "undef $self",
    and call it just before you exit. Then you get the destruction order you
    want.


    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Mar 9, 2006
    #15
  16. Ivan Fomichev

    Guest

    "Ivan Fomichev" <> wrote:
    > I'm glad to inform, that I've found a satisfactory workaround. END can
    > be used instead of DESTROY. Though I am not sure, if there can be side
    > effects of such use.


    Yes, END is better than my suggestion of finalize, because it doesn't
    need to be called explicitly. (Or maybe it is worse, because then it is
    harder to manually control the order of finalization of different classes,
    if that matters.)

    > use strict;
    > package Singleton;
    > use Data::Dumper;
    > my $self;
    > sub new {
    > print +(caller(0))[3], "\n";
    > my ($class) = shift;
    > return $self if $self;
    >
    > my $item = Item->new();
    > $self = bless \$item => $class;
    > print Dumper($self);
    > return $self;
    > }
    >
    > sub END {
    > print +(caller(0))[3], "\n";
    > print Dumper($self);
    > }



    However, the Singleton sticks around, holding a reference to Item, so Item
    is still being destroyed during global destruction in your code. If you
    want Item to be destroyed during reference-based destruction, then you need
    to add "undef $self" to the Singleton's END routine.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Mar 9, 2006
    #16
  17. Ivan Fomichev

    brian d foy Guest

    In article <20060309113656.198$>, <>
    wrote:

    > The lexical variable $self doesn't seem to go away until the mark and sweep
    > phase, therefore the reference-chain it holds survive until after
    > reference- based phase is done.


    You can weaken (see Scalar:Util) the initial singleton variable so it
    does count in the reference count. After you do that, things should
    happen more like what you expect. :)
    *** Free account sponsored by SecureIX.com ***
    *** Encrypt your Internet usage with a free VPN account from http://www.SecureIX.com ***
    brian d foy, Mar 10, 2006
    #17
  18. Ivan Fomichev

    Guest

    brian d foy <> wrote:
    > In article <20060309113656.198$>, <>
    > wrote:
    >
    > > The lexical variable $self doesn't seem to go away until the mark and
    > > sweep phase, therefore the reference-chain it holds survive until after
    > > reference- based phase is done.

    >
    > You can weaken (see Scalar:Util) the initial singleton variable so it
    > does count in the reference count. After you do that, things should
    > happen more like what you expect. :)


    Well, that depends on what you expect. :)

    If you do that, then it isn't really a singleton anymore, the way I see it.
    At any given time, you will have only one instance, but over time you may
    have different ones.

    If you have:

    package main;
    {
    my $s = Singleton->new();
    }
    {
    my $s = Singleton->new();
    }

    Then the two $s will not be the same object, because it was destroyed
    when the first $s went out of scope, so the "singleton" had to be recreated
    for second "new".

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Mar 10, 2006
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    439
    mrstephengross
    Jul 25, 2005
  2. Proton Projects - Moin

    Singleton - Whether Cloneable overrides Singleton

    Proton Projects - Moin, Mar 26, 2007, in forum: Java
    Replies:
    4
    Views:
    3,247
    Proton Projects - Moin
    Mar 27, 2007
  3. Øyvind Isaksen
    Replies:
    1
    Views:
    965
    Øyvind Isaksen
    May 18, 2007
  4. Wilhelm
    Replies:
    1
    Views:
    164
  5. Trans
    Replies:
    12
    Views:
    275
    Robert Klemme
    Sep 14, 2007
Loading...

Share This Page