Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Tracing zombie variables.

by ash (Monk)
on Aug 29, 2002 at 09:03 UTC ( [id://193705]=perlquestion: print w/replies, xml ) Need Help??

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

I'm wondering how I can easily locate variables that has a
reference count >= 1, but has no referents.

I'm implementing a doubly-linked list, and have been drawing the execution
steps of the program to locate possible memory-leaks, but I'm afraid something
might have slipped my head.

I don't want to implement it using OO because of the overhead that follows.

-- Ash/asksh <ask@unixmonks.net>

Replies are listed 'Best First'.
Re: Tracing zombie variables.
by demerphq (Chancellor) on Aug 29, 2002 at 09:24 UTC
    UPDATE:

    I didnt notice your comment about OO when i first wrote this, so im comenting now. Your concern about OO is unfounded. The overhead to which you refer is a consequence of method call look up. In the case I proposed this is not really a factor as the only method calls that I suggest you support is new() and DESTROY() and they only get called once per object and thus the overhead is negligable.

    END UPDATE

    Well, there arent really any good ways to do this. However one trick that you may find useful (assuming you are doing OO and that your nodes are discrete objects) is to keep track of the number of created nodes and the number of destroyed nodes, like so

    package LL::Node; { my $allocated=0 sub new { $allocated++; bless {},$_[0]; } sub DESTROY { $allocated--; } sub END { warn "There were $allocated nodes that have not been properly free +d dusing destruction.\n" if $allocated; } } # other stuff
    This way you will at least know how many objects with cyclic references that havent been freed. Of course you could just use the DESTROY sub to ensure that any links are broken
    sub DESTROY { $allocated--; $_[0]->{next}=undef; $_[0]->{prev}=undef; }
    Assuming of course that you are using hash based nodes...

    Also if you wanted to get into really deep mojo you could use Scalar::Util which provides a way to make a "weak" reference, but personally i wouldnt do that...

    HTH

    Yves / DeMerphq
    ---
    Software Engineering is Programming when you can't. -- E. W. Dijkstra (RIP)

        > In the case I proposed this is not really a factor as the
        > only method calls that I suggest you support is new() and
        > DESTROY() and they only get called once per object and
        > thus the overhead is negligable.

      You're indeed right demerphq.
      I was blinded by the method explained in Mastering Algorithms with Perl
      which has methods for next() and prev().

      Thank you for enlightenment.

      -- 
      Ash/asksh <ask@unixmonks.net>

        s blinded by the method explained in Mastering Algorithms with Perl which has methods for next() and prev().

        And rightly so. You _should_ supply such methods. If there is any chance that someone outside of your module will need to access these methods/attributes then you should provide a method interface for them to do so.

        However inside of your module, the one that manipulates the actual data structure, you can certainly make the design decision to use the underlying object implementation. After all it is your code and your implementation so the only one that you can burn is yourself.

        For instance I completely bypass the method interface for my node objects in my Treap implementation. However my node is a subclass of a Class::Struct so that anything outside can have something more stable to utilize. (ie no nasty suprises for users that use the method interface).

        Yves / DeMerphq
        ---
        Software Engineering is Programming when you can't. -- E. W. Dijkstra (RIP)

Re: Tracing zombie variables.
by PodMaster (Abbot) on Aug 29, 2002 at 10:49 UTC
    The answer is simple, don't create such variables. There is already enough evil in the world.

    or if you still feel like being evil, check out WeakRef and Devel::WeakRef

    update: Timmay! Evil! Timmay! ;-)

    ____________________________________________________
    ** The Third rule of perl club is a statement of fact: pod is sexy.

      Bah, I write stuff with cyclic refs all the time. Many useful data structres include cyclic refs. For instance I shall be posting my threaded treap implementation in the next few days and it has cyclic refs galore, all of which are correctly removed by using the correct DESTROY() subroutine (in fact my answer to ash was based on a solution I came up with to ensure that I wasnt leaking memory...)

      :-)

      Yves / DeMerphq
      ---
      Software Engineering is Programming when you can't. -- E. W. Dijkstra (RIP)

        indeed. cyclic references *can* be a bitch though, especially in situations where one has a lot of inter-operating objects in a persistent Perl interpreter, eg mod_perl. consider:

        #!/usr/bin/perl -w use strict; package A; { sub new { my $class = shift; return bless( { @_ }, $class ); } sub DESTROY { warn "$_[0] just died"; } sub set { $_[0]->{ $_[1] } = $_[2]; } } package B; { @B::ISA = qw/ A /; } package C; { @C::ISA = qw/ A /; } package main; warn "doing something...\n"; do_something(); warn "doing something else (again)...\n"; do_something(); warn "exiting program...\n"; exit; sub do_something { warn "entering block...\n"; my $a = new A (); my $b = new B (); my $c = new C (); $b->set( C => $c ); $c->set( B => $b ); warn "exiting block\n"; } # output of above: doing something... entering block... exiting block... A=HASH(0x804b424) just died at ./test_objects.pl line 13. doing something else (again)... entering block... exiting block... A=HASH(0x805d074) just died at ./test_objects.pl line 13. exiting program... C=HASH(0x805bb10) just died at ./test_objects.pl line 13 during global + destruction. B=HASH(0x805b9f0) just died at ./test_objects.pl line 13 during global + destruction. C=HASH(0x805d08c) just died at ./test_objects.pl line 13 during global + destruction. B=HASH(0x804b424) just died at ./test_objects.pl line 13 during global + destruction.

        Voila, an unclaimed cyclic reference every time you call do_something(), or any other code that creates object that store references to each other. This is surprisingly easy to do in a large, multi object/reference system, and irritatingly difficult to track down when it happens. meanwhile, your httpd's are growing and growing with every page request....

        matt

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://193705]
Approved by rob_au
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2024-04-24 19:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found