.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Test::Refcount 3pm" .TH Test::Refcount 3pm "2014-05-23" "perl v5.18.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" "Test::Refcount" \- assert reference counts on objects .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& use Test::More tests => 2; \& use Test::Refcount; \& \& use Some::Class; \& \& my $object = Some::Class\->new(); \& \& is_oneref( $object, \*(Aq$object has a refcount of 1\*(Aq ); \& \& my $otherref = $object; \& \& is_refcount( $object, 2, \*(Aq$object now has 2 references\*(Aq ); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" The Perl garbage collector uses simple reference counting during the normal execution of a program. This means that cycles or unweakened references in other parts of code can keep an object around for longer than intended. To help avoid this problem, the reference count of a new object from its class constructor ought to be 1. This way, the caller can know the object will be properly DESTROYed when it drops all of its references to it. .PP This module provides two test functions to help ensure this property holds for an object class, so as to be polite to its callers. .PP If the assertion fails; that is, if the actual reference count is different to what was expected, either of the following two modules may be used to assist the developer in finding where the references are. .IP "\(bu" 4 If Devel::FindRef module is installed, a reverse-references trace is printed to the test output. .IP "\(bu" 4 If Devel::MAT is installed, this test module will use it to dump the state of the memory after a failure. It will create a \fI.pmat\fR file named the same as the unit test, but with the trailing \fI.t\fR suffix replaced with \&\fI\-TEST.pmat\fR where \f(CW\*(C`TEST\*(C'\fR is the number of the test that failed (in case there was more than one). .PP See the examples below for more information. .SH "FUNCTIONS" .IX Header "FUNCTIONS" .ie n .SS "is_refcount( $object, $count, $name )" .el .SS "is_refcount( \f(CW$object\fP, \f(CW$count\fP, \f(CW$name\fP )" .IX Subsection "is_refcount( $object, $count, $name )" Test that \f(CW$object\fR has \f(CW$count\fR references to it. .ie n .SS "is_oneref( $object, $name )" .el .SS "is_oneref( \f(CW$object\fP, \f(CW$name\fP )" .IX Subsection "is_oneref( $object, $name )" Assert that the \f(CW$object\fR has only 1 reference to it. .SH "EXAMPLE" .IX Header "EXAMPLE" Suppose, having written a new class \f(CW\*(C`MyBall\*(C'\fR, you now want to check that its constructor and methods are well-behaved, and don't leak references. Consider the following test script: .PP .Vb 2 \& use Test::More tests => 2; \& use Test::Refcount; \& \& use MyBall; \& \& my $ball = MyBall\->new(); \& is_oneref( $ball, \*(AqOne reference after construct\*(Aq ); \& \& $ball\->bounce; \& \& # Any other code here that might be part of the test script \& \& is_oneref( $ball, \*(AqOne reference just before EOF\*(Aq ); .Ve .PP The first assertion is just after the constructor, to check that the reference returned by it is the only reference to that object. This fact is important if we ever want \f(CW\*(C`DESTROY\*(C'\fR to behave properly. The second call is right at the end of the file, just before the main scope closes. At this stage we expect the reference count also to be one, so that the object is properly cleaned up. .PP Suppose, when run, this produces the following output (presuming \&\f(CW\*(C`Devel::FindRef\*(C'\fR is available): .PP .Vb 10 \& 1..2 \& ok 1 \- One reference after construct \& not ok 2 \- One reference just before EOF \& # Failed test \*(AqOne reference just before EOF\*(Aq \& # at demo.pl line 16. \& # expected 1 references, found 2 \& # MyBall=ARRAY(0x817f880) is \& # +\- referenced by REF(0x82c1fd8), which is \& # | in the member \*(Aqself\*(Aq of HASH(0x82c1f68), which is \& # | referenced by REF(0x81989d0), which is \& # | in the member \*(Aqcycle\*(Aq of HASH(0x82c1f68), which was seen before. \& # +\- referenced by REF(0x82811d0), which is \& # in the lexical \*(Aq$ball\*(Aq in CODE(0x817fa00), which is \& # the main body of the program. \& # Looks like you failed 1 test of 2. .Ve .PP From this output, we can see that the constructor was well-behaved, but that a reference was leaked by the end of the script \- the reference count was 2, when we expected just 1. Reading the trace output, we can see that there were 2 references that \f(CW\*(C`Devel::FindRef\*(C'\fR could find \- one stored in the \f(CW$ball\fR lexical in the main program, and one stored in a \s-1HASH.\s0 Since we expected to find the \f(CW$ball\fR lexical variable, we know we are now looking for a leak in a hash somewhere in the code. From reading the test script, we can guess this leak is likely to be in the \fIbounce()\fR method. Furthermore, we know that the reference to the object will be stored in a \s-1HASH\s0 in a member called \f(CW\*(C`self\*(C'\fR. .PP By reading the code which implements the \fIbounce()\fR method, we can see this is indeed the case: .PP .Vb 6 \& sub bounce \& { \& my $self = shift; \& my $cycle = { self => $self }; \& $cycle\->{cycle} = $cycle; \& } .Ve .PP From reading the \f(CW\*(C`Devel::FindRef\*(C'\fR output, we find that the \s-1HASH\s0 this object is referenced in also contains a reference to itself, in a member called \&\f(CW\*(C`cycle\*(C'\fR. This comes from the last line in this function, a line that purposely created a cycle, to demonstrate the point. While a real program probably wouldn't do anything quite this obvious, the trace would still be useful in finding the likely cause of the leak. .PP If \f(CW\*(C`Devel::FindRef\*(C'\fR is unavailable, then these detailed traces will not be produced. The basic reference count testing will still take place, but a smaller message will be produced: .PP .Vb 7 \& 1..2 \& ok 1 \- One reference after construct \& not ok 2 \- One reference just before EOF \& # Failed test \*(AqOne reference just before EOF\*(Aq \& # at demo.pl line 16. \& # expected 1 references, found 2 \& # Looks like you failed 1 test of 2. .Ve .SH "BUGS" .IX Header "BUGS" .IP "\(bu" 4 Temporaries created on the stack .Sp Code which creates temporaries on the stack, to be released again when the called function returns does not work correctly on perl 5.8 (and probably before). Examples such as .Sp .Vb 1 \& is_oneref( [] ); .Ve .Sp may fail and claim a reference count of 2 instead. .Sp Passing a variable such as .Sp .Vb 2 \& my $array = []; \& is_oneref( $array ); .Ve .Sp works fine. Because of the intention of this test module; that is, to assert reference counts on some object stored in a variable during the lifetime of the test script, this is unlikely to cause any problems. .SH "ACKNOWLEDGEMENTS" .IX Header "ACKNOWLEDGEMENTS" Peter Rabbitson \- for suggesting using core's \f(CW\*(C`B\*(C'\fR instead of \f(CW\*(C`Devel::Refcount\*(C'\fR to obtain refcounts .SH "AUTHOR" .IX Header "AUTHOR" Paul Evans