1Test::Refcount(3)     User Contributed Perl Documentation    Test::Refcount(3)
2
3
4

NAME

6       "Test::Refcount" - assert reference counts on objects
7

SYNOPSIS

9          use Test::More tests => 2;
10          use Test::Refcount;
11
12          use Some::Class;
13
14          my $object = Some::Class->new();
15
16          is_oneref( $object, '$object has a refcount of 1' );
17
18          my $otherref = $object;
19
20          is_refcount( $object, 2, '$object now has 2 references' );
21

DESCRIPTION

23       The Perl garbage collector uses simple reference counting during the
24       normal execution of a program. This means that cycles or unweakened
25       references in other parts of code can keep an object around for longer
26       than intended. To help avoid this problem, the reference count of a new
27       object from its class constructor ought to be 1. This way, the caller
28       can know the object will be properly DESTROYed when it drops all of its
29       references to it.
30
31       This module provides two test functions to help ensure this property
32       holds for an object class, so as to be polite to its callers.
33
34       If the assertion fails; that is, if the actual reference count is
35       different to what was expected, either of the following two modules may
36       be used to assist the developer in finding where the references are.
37
38       •   If Devel::MAT is installed, this test module will use it to dump
39           the state of the memory after a failure. It will create a .pmat
40           file named the same as the unit test, but with the trailing .t
41           suffix replaced with -TEST.pmat where "TEST" is the number of the
42           test that failed (in case there was more than one).
43
44       •   If Devel::FindRef module is installed, a reverse-references trace
45           is printed to the test output.
46
47       See the examples below for more information.
48

FUNCTIONS

50   is_refcount
51          is_refcount( $object, $count, $name )
52
53       Test that $object has $count references to it.
54
55   is_oneref
56          is_oneref( $object, $name )
57
58       Assert that the $object has only 1 reference to it.
59
60   refcount
61          $count = refcount( $object )
62
63       Since version 0.09.
64
65       Returns the reference count of the given object as used by the test
66       functions.  This is useful for making tests that don't care what the
67       count is before they start, but simply assert that the count hasn't
68       changed by the end.
69
70          use Test::Refcount import => [qw( is_refcount refcount )];
71          {
72             my $count = refcount( $object );
73
74             do_something( $object );
75
76             is_refcount( $object, $count, 'do_something() preserves refcount' );
77          }
78

EXAMPLE

80       Suppose, having written a new class "MyBall", you now want to check
81       that its constructor and methods are well-behaved, and don't leak
82       references. Consider the following test script:
83
84          use Test::More tests => 2;
85          use Test::Refcount;
86
87          use MyBall;
88
89          my $ball = MyBall->new();
90          is_oneref( $ball, 'One reference after construct' );
91
92          $ball->bounce;
93
94          # Any other code here that might be part of the test script
95
96          is_oneref( $ball, 'One reference just before EOF' );
97
98       The first assertion is just after the constructor, to check that the
99       reference returned by it is the only reference to that object. This
100       fact is important if we ever want "DESTROY" to behave properly. The
101       second call is right at the end of the file, just before the main scope
102       closes. At this stage we expect the reference count also to be one, so
103       that the object is properly cleaned up.
104
105       Suppose, when run, this produces the following output (presuming
106       Devel::MAT::Dumper is available):
107
108          1..2
109          ok 1 - One reference after construct
110          not ok 2 - One reference just before EOF
111          #   Failed test 'One reference just before EOF'
112          #   at ex.pl line 26.
113          #   expected 1 references, found 2
114          # SV address is 0x55e14c310278
115          # Writing heap dump to ex-2.pmat
116          # Looks like you failed 1 test of 2.
117
118       This has written a ex-2.pmat file we can load using the "pmat" shell
119       and use the "identify" command on the given address to find where it
120       went:
121
122          $ pmat ex-2.pmat
123          Perl memory dumpfile from perl 5.28.1 threaded
124          Heap contains 25233 objects
125          pmat> identify 0x55e14c310278
126          HASH(0)=MyBall at 0x55e14c310278 is:
127          ├─(via RV) the lexical $ball at depth 1 of CODE() at 0x55e14c3104a0=main_cv, which is:
128          │ └─the main code
129          └─(via RV) value {self} of HASH(2) at 0x55e14cacb860, which is (*A):
130            └─(via RV) value {cycle} of HASH(2) at 0x55e14cacb860, which is:
131              itself
132
133       (This document isn't intended to be a full tutorial on Devel::MAT and
134       the "pmat" shell; for that see Devel::MAT::UserGuide).
135
136       Alternatively, this produces the following output when using
137       Devel::FindRef instead:
138
139          1..2
140          ok 1 - One reference after construct
141          not ok 2 - One reference just before EOF
142          #   Failed test 'One reference just before EOF'
143          #   at demo.pl line 16.
144          #   expected 1 references, found 2
145          # MyBall=ARRAY(0x817f880) is
146          # +- referenced by REF(0x82c1fd8), which is
147          # |     in the member 'self' of HASH(0x82c1f68), which is
148          # |        referenced by REF(0x81989d0), which is
149          # |           in the member 'cycle' of HASH(0x82c1f68), which was seen before.
150          # +- referenced by REF(0x82811d0), which is
151          #       in the lexical '$ball' in CODE(0x817fa00), which is
152          #          the main body of the program.
153          # Looks like you failed 1 test of 2.
154
155       From this output, we can see that the constructor was well-behaved, but
156       that a reference was leaked by the end of the script - the reference
157       count was 2, when we expected just 1. Reading the trace output, we can
158       see that there were 2 references that could be found - one stored in
159       the $ball lexical in the main program, and one stored in a HASH. Since
160       we expected to find the $ball lexical variable, we know we are now
161       looking for a leak in a hash somewhere in the code. From reading the
162       test script, we can guess this leak is likely to be in the bounce()
163       method. Furthermore, we know that the reference to the object will be
164       stored in a HASH in a member called "self".
165
166       By reading the code which implements the bounce() method, we can see
167       this is indeed the case:
168
169          sub bounce
170          {
171             my $self = shift;
172             my $cycle = { self => $self };
173             $cycle->{cycle} = $cycle;
174          }
175
176       From reading the tracing output, we find that the HASH this object is
177       referenced in also contains a reference to itself, in a member called
178       "cycle". This comes from the last line in this function, a line that
179       purposely created a cycle, to demonstrate the point. While a real
180       program probably wouldn't do anything quite this obvious, the trace
181       would still be useful in finding the likely cause of the leak.
182
183       If neither "Devel::MAT::Dumper" nor "Devel::FindRef" are available,
184       then these detailed traces will not be produced. The basic reference
185       count testing will still take place, but a smaller message will be
186       produced:
187
188          1..2
189          ok 1 - One reference after construct
190          not ok 2 - One reference just before EOF
191          #   Failed test 'One reference just before EOF'
192          #   at demo.pl line 16.
193          #   expected 1 references, found 2
194          # Looks like you failed 1 test of 2.
195

BUGS

197       •   Temporaries created on the stack
198
199           Code which creates temporaries on the stack, to be released again
200           when the called function returns does not work correctly on perl
201           5.8 (and probably before). Examples such as
202
203              is_oneref( [] );
204
205           may fail and claim a reference count of 2 instead.
206
207           Passing a variable such as
208
209              my $array = [];
210              is_oneref( $array );
211
212           works fine. Because of the intention of this test module; that is,
213           to assert reference counts on some object stored in a variable
214           during the lifetime of the test script, this is unlikely to cause
215           any problems.
216

ACKNOWLEDGEMENTS

218       Peter Rabbitson <ribasushi@cpan.org> - for suggesting using core's "B"
219       instead of "Devel::Refcount" to obtain refcounts
220

AUTHOR

222       Paul Evans <leonerd@leonerd.org.uk>
223
224
225
226perl v5.34.0                      2022-01-21                 Test::Refcount(3)
Impressum