NAME

Test::Weaken - Test that freed references are, indeed, freed

SYNOPSIS

use Test::Weaken qw(leaks);
use Data::Dumper;
use Math::BigInt;
use Math::BigFloat;

my $good_test = sub {
   my $obj1 = new Math::BigInt('42');
   my $obj2 = new Math::BigFloat('7.11');
   [ $obj1, $obj2 ];
};  

my $bad_test = sub {
   my $array = [ 42, 711 ];
   push @{$array}, $array;
   $array;
};

my $bad_destructor = sub { "I don't work" };

if ( !leaks( $good_test ) ) {
    print "No leaks in test 1\n";
} else {
    print "There were memory leaks from test 1!\n";
}

my $test = Test::Weaken::leaks({
    constructor => $bad_test,
    destructor  => $bad_destructor,
});
if ( $test ) {
    my $unfreed_proberefs = $test->unfreed_proberefs();
    my $unfreed_count = @{$unfreed_proberefs};
    printf "Test 2: %d of %d original references were not freed\n",
        $test->unfreed_count(),
        $test->probe_count();
    print "These are the probe references to the unfreed objects:\n";
    for my $proberef ( @{$unfreed_proberefs} ) {
        print Data::Dumper->Dump( [$proberef], ['unfreed'] );
    }
}

DESCRIPTION

Memory leaks happen when the memory allocated by objects which are no longer needed is not completely deallocated. (Deallocating memory is also called freeing it.) As an example in Perl, a memory leak will occur if an object contains circular references and does not have an effective scheme for weakening references or cleaning up memory. Leaked memory is a useless overhead. Leaky memory objects can significantly impact system performance. They can also cause the application with the leaks to abend due to lack of memory.

Test::Weaken allows you to check that an object does not leak memory. If it does leak memory, Test::Weaken allows you to examine the "leaked" memory objects, even objects that would usually be inaccessible. It performs this magic by creating a set of weakened probe references, as explained below.

The test object is passed as the return value of a closure. The closure should return the primary test reference, a reference to the test object. Test::Weaken checks the memory that can be found by following the primary test reference. Starting with the primary test reference, arrays, hashes, weak references and strong references are followed recursively and to unlimited depth.

Test::Weaken handles circular references gracefully. A major purpose of Test::Weaken is to test schemes for circular references. To avoid infinite loops, Test::Weaken records all the memory objects it visits, and will not visit the same memory object twice.

Why the Test Object is Passed via a Closure

Test::Weaken does not accept its test object or its primary test reference directly as an argument. Instead, Test::Weaken receives its test objects from test object constructors.

Why so roundabout? It turns out the indirect way is the easiest. The test object must not have any strong references to it from outside. It takes some craft to create the test object in Test::Weaken's calling environment without leaving any reference to the test object in the calling environment, and it is easy to make a mistake.

When the calling environment retains a reference to memory contained in the test object, the result is a memory leak. Mistakes in setting up the test object, therefore, appear as false reports of memory leaks. These are hard to distinguish from the real thing.

Memory objects local to a closure will be destroyed when the closure returns, and any references they held will be released. When the test object is set up entirely in a closure, using only memory objects local to that closure, it becomes relatively easy to be sure that nothing is left behind that will hold an unintended reference to memory inside the test object.

To encourage this discipline, Test::Weaken requires that its primary test reference be the return value of a closure. This makes what is the safe and almost always right thing to do, also the easiest thing to do.

Of course, if the user wants to, within the closure he can refer to data in global and other scopes from outside the closure. The user can also return memory objects created partially or completely from data in any or all of those scopes. Subverting Test::Weaken's "closure data only" discipline can be done with only a small amount of trouble, certainly by comparison to the grief that the user is exposing himself to.

Returns and Exceptions

The methods of Test::Weaken do not return errors. Errors are always thrown as exceptions.

METHODS

leaks

Arguments to the leaks static method may be passed as a reference to a hash of named arguments, or directly as code references. leaks returns a Test::Weaken object if it found leaks, and a Perl false value otherwise. Users simply wanting to know if there were leaks can check whether the return value of leaks is a Perl true or false. Users who want to look more closely at leaks can use other methods to interrogate the return value.

A test object constructor is a required argument. It must be a code reference. If passed directly, it must be the first argument to leaks. Otherwise, it must be the value of the constructor named argument.

The test object constructor should build the test object and create a primary test reference to it. The return value of the test object constructor must be the primary test reference. It is best to construct the test object inside the test object constructor as much as possible. That is the easiest way to construct a test object with no references into it from the calling environment.

The test object destructor is an optional argument. If specified, it must be a code reference. If passed directly, it must be the second argument to leaks. Otherwise, it must be the value of the destructor named argument.

If specified, the test object destructor is called just before the primary test reference is undefined. It will be passed one argument, the primary test reference. One purpose for the test object destructor is to allow Test::Weaken to work with objects that require a destructor to be called on them when they are freed. For example, some of the objects created by Gtk2-Perl are of this type.

unfreed_proberefs

Returns a reference to an array of probe references to the unfreed memory objects. The user may examine these to find the source of a leak, or to produce her own statistics.

The array is returned as a reference because in some applications it can be quite long. The array contains probe references, not the memory objects themselves. This is because some memory objects, such as other arrays and hashes, cannot be elements of arrays. Weak references are another reason for not returning an array containing the memory objects themselves. Directly copying the weak references would strengthen them.

unfreed_count

Returns the count of unfreed memory objects. This count will be exactly the length of the array referred to by the return value of the unfreed_proberefs method.

probe_count

Returns the total number of probe references in the test, including references to freed memory objects. This is the count of probe references after Test::Weaken was finished following the test object reference recursively, but before it called the test object destructor and undefined the test object reference.

ADVANCED TECHNIQUES

The simplest way to use Test::Weaken is to call the leaks method, and treat its return value as a Perl true or false. But you can also use Test::Weaken for tracing leaks. Here are some potentially helpful techniques.

Tracing Memory Leaks

The unfreed_proberefs method returns an array containing the unfreed memory objects and can be used to find the source of leaks. If circumstances allow you to add elements to the arrays and hashes, you might find it useful to "tag" them for tracking purposes.

You can uniquely identify memory objects using the referent addresses of the probe references. A referent address can be determined by using the refaddr method of Scalar::Util. You can also obtain the referent address of a reference by adding zero to the reference.

Note that in other Perl documentation, the term "reference address" is often used when a referent address is meant. Any given reference has both a reference address and a referent address. The reference address is the reference's own location in memory. The referent address is the address of the memory object to which it refers. It is the referent address that interests us here and, happily, it is the referent address that addition of zero and refaddr return.

Testing Objects Which Refer to Persistent or External Memory

Your test object may refer to memory that is considered to be "outside" the object: external memory. In other cases, the specification of the object may allow certain memory referred to by the object to persist after the object is destroyed: persistent memory. External memory is often expected to be persistent memory.

To check for leaks in objects which refer to persistent memory, you can examine the unfreed objects returned by unfreed_proberefs and eliminate the memory objects which are persistent. The remaining objects will be the memory leaks.

If You Really Must Test Deallocation of a Global

As explained above, Test::Weaken receives its test object as the return value of a closure. It does this because it's tricky to create objects in a global environment without keeping references to them. References accidently held by the calling environment will cause false leak reports.

But you may have no other choice. The test object constructor can refer to data in a scope which is not local to the constructor. It can also return a primary test reference built using this data. Nothing prevents a test object constructor from, for example, simply returning a reference it finds in global scope as the primary test reference.

EXPORT

By default, Test::Weaken exports nothing. Optionally, leaks may be exported.

LIMITATIONS

Test::Weaken does not check for leaked code references or look inside them.

IMPLEMENTATION

Test::Weaken first recurses through the test object. It follows all weak and strong references, arrays and hashes. The test object is explored to unlimited depth, looking for memory objects, that is, objects which have memory allocated. Visited memory objects are tracked, and no memory object is visited twice. For each memory object, a probe reference is created.

Once recursion through the test object is complete, the probe references are weakened, so that they will not interfere with normal deallocation of memory. Next, the test object destructor is called, if there is one.

Finally, the primary test reference is undefined. This should trigger the complete deallocation of all memory held by the test object. To check that this happened, Test::Weaken dereferences the probe references. If the referent of a probe reference was deallocated, the value of that probe reference will be undef. If a probe reference is still defined at this point, it refers to an unfreed memory object.

AUTHOR

Jeffrey Kegler

BUGS

Please report any bugs or feature requests to bug-test-weaken at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Weaken. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Test::Weaken

You can also look for information at:

SEE ALSO

Potential users will want to compare Test::Memory::Cycle and Devel::Cycle, which examine existing structures non-destructively. Devel::Leak also covers similar ground, although it requires Perl to be compiled with -DDEBUGGING in order to work. Devel::Cycle looks inside closures if PadWalker is present, a feature Test::Weaken does not have at present.

ACKNOWLEDGEMENTS

Thanks to jettero, Juerd and perrin of Perlmonks for their advice. Thanks to Lincoln Stein (developer of Devel::Cycle) for test cases and other ideas.

After the first release of Test::Weaken, Kevin Ryde made several important suggestions and provided test cases. These provided the impetus for version 2.000000.

LICENSE AND COPYRIGHT

Copyright 2007-2009 Jeffrey Kegler, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.