Beefy Boxes and Bandwidth Generously Provided by pair Networks Joe
go ahead... be a heretic
 
PerlMonks  

A way to test that circular references are actually freed

by Jeffrey Kegler (Friar)
on Oct 10, 2007 at 00:42 UTC ( #643834=perlmeditation: print w/ replies, xml ) Need Help??

Occasionally you'll have a module that requires circular references. Of course, you'll want it to be well-behaved, so you use weaken statements on selected references so that, when the objects are freed, all the memory does indeed go away.

Putting the weaken statement in the right place can be tricky, and unlike most bugs which are all too evident when you don't get the answer you need, any mistake results in a memory leak, which you might take a while to notice.

So I wrote a test module for weakening. Give it an an anonymous subroutine which returns a reference, and it will undef the result, then check that all the memory was indeed freed just the way it was supposed to be.

Does this duplicate anything currently in CPAN? If not, I'll document it, package it, and contribute it.

UPDATE: A beta release is now in CPAN.

jeffrey kegler

Comment on A way to test that circular references are actually freed
Re: A way to test that circular references are actually freed
by jettero (Monsignor) on Oct 10, 2007 at 00:48 UTC

    I'm not aware of anything on CPAN, which doesn't mean there isn't anything, but does it differ much from adding a DESTROY { warn "$_[0] is dying" } to a blessed ref? I'm curious to read how it works if nothing else.

    You might even post some of it in a code block... it's not like someone would "steal" it or something...

    UPDATE: It definitely sounds iteresting to me. And I'd still like to read through it.

    -Paul

      It uses trickery from the Scalar::Util module. There were a lot of gotchas involved -- avoiding autovivification and avoiding strengthening weak references by copying. Limitations are that you've got to pass a closure and create the object in that. And it's totally destructive (at least it is when the test is successful). Anything returned by the closure is potentially (and hopefully) gone forever.

      Perhaps the most severe limitation is that it can't have references to any globals or any memory which is supposed to hang around -- it's not smart about that, but just assumes everything must go. If there's interest I may in a future version allow the caller to specify exceptions

      The basic trick is to create weak references to the strong references and strong references to the weak references, free up the base reference, and see if all the others go to undefined. I've just added some code to make it smart about undefs in the original object.

      I'll get it on CPAN in a couple of days, and you'll be able to read the code. It's not long.

      jeffrey

        Here it is in all its alpha status glory. (It needs some formatting and more comments.) It passes a simple test suite, and has handled very complicated structures from another CPAN project (the reason I originally wrote it). I've applied to PAUSE for the name Test::Weaken.

        There does seem to be a bug with the count of the total references, but it does not affect the count of freed references, and therefore fail/succeed reporting is unaffected.

        UPDATE: I've removed the code. Test::Weaken is now on CPAN and anyone can see the latest version there. It's still alpha, but it has a start in the way of documentation and there are test scripts, which make good examples.

        The version in this post did turn out to have the bug mentioned above, which is fixed in the CPAN version. I was reluctant to post the code but senior monks asked more than once to see it, and this humblest and most unworthy of Sextons was unwilling to refuse. Those who really feel they need to look at my first attempts, can look at earliest versions on backpan.

        jeffrey

Re: A way to test that circular references are actually freed
by perrin (Chancellor) on Oct 10, 2007 at 03:40 UTC
      Thanks for pointing me to Test::Memory::Cycle. It and Devel::Cycle (on which it's based) appear to work on a predictive basis. If they find no cycles, or only weakened ones, you could expect there to be no memory leaks.

      The proposed Test::Weaken checks both before and after the fact to see that the memory was freed. It certainly would be useful in testing the other approach. :-)

      I also now find a Devel::Leak, which actually looks at the Perl internals. However, it requires Perl to have been compiled with the -DDEBUGGING flag set, whereas Test::Weaken works on Perl compiled the ordinary way.

      Perhaps which approach is best is a matter of specific situation and taste. I'd think the user would want to have modules implementing both approaches available in CPAN and to be able to take their choice. TIMTOWTDI and all that.

      I do notice that Devel::Cycle can handle cycles that happen via references to closures, something my code doesn't at this point.

      thanks, very helpful, jeffrey

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://643834]
Approved by grep
Front-paged by ikegami
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2014-04-21 10:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (492 votes), past polls