dwww Home | Manual pages | Find package

Test2:...fcount(3perl)  Perl Programmers Reference Guide Test2:...fcount(3perl)

NAME
       "Test2::Tools::Refcount" - assert reference counts on objects

SYNOPSIS
          use Test2::Tools::Refcount;

          use Some::Class;
          my $object = Some::Class->new();

          is_oneref( $object, '$object has a refcount of 1' );

          my $otherref = $object;

          is_refcount( $object, 2, '$object now has 2 references' );

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.

       This module provides two test functions to help ensure this property
       holds for an object class, so as to be polite to its callers.

       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.

       •   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 .pmat file
           named the same as the unit test, but with  the  trailing  .t  suffix
           replaced with -TEST.pmat where "TEST" is the number of the test that
           failed (in case there was more than one).

       See the examples below for more information.

FUNCTIONS
   is_refcount
          is_refcount( $object, $count, $name )

       Test that $object has $count references to it.

   is_oneref
          is_oneref( $object, $name )

       Assert that the $object has only 1 reference to it.

   refcount
          $count = refcount( $object )

       Returns  the  reference  count  of  the given object as used by the test
       functions.  This is useful for making tests that  don't  care  what  the
       count  is  before  they  start,  but simply assert that the count hasn't
       changed by the end.

          use Test2::Tools::Refcount import => [qw( is_refcount refcount )];
          {
             my $count = refcount( $object );

             do_something( $object );

             is_refcount( $object, $count, 'do_something() preserves refcount' );
          }

EXAMPLE
       Suppose, having written a new class "MyBall", you now want to check that
       its constructor and methods are well-behaved, and don't leak references.
       Consider the following test script:

          use Test::More tests => 2;
          use Test2::Tools::Refcount;

          use MyBall;

          my $ball = MyBall->new();
          is_oneref( $ball, 'One reference after construct' );

          $ball->bounce;

          # Any other code here that might be part of the test script

          is_oneref( $ball, 'One reference just before EOF' );

       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 "DESTROY" 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.

       Suppose,  when  run,  this  produces  the  following  output  (presuming
       Devel::MAT::Dumper is available):

          1..2
          ok 1 - One reference after construct
          not ok 2 - One reference just before EOF
          #   Failed test 'One reference just before EOF'
          #   at ex.pl line 26.
          #   expected 1 references, found 2
          # SV address is 0x55e14c310278
          # Writing heap dump to ex-2.pmat
          # Looks like you failed 1 test of 2.

       This has written a ex-2.pmat file we can load using the "pmat" shell and
       use the "identify" command on the given address to find where it went:

          $ pmat ex-2.pmat
          Perl memory dumpfile from perl 5.28.1 threaded
          Heap contains 25233 objects
          pmat> identify 0x55e14c310278
          HASH(0)=MyBall at 0x55e14c310278 is:
          ├─(via RV) the lexical $ball at depth 1 of CODE() at 0x55e14c3104a0=main_cv, which is:
          │ └─the main code
          └─(via RV) value {self} of HASH(2) at 0x55e14cacb860, which is (*A):
            └─(via RV) value {cycle} of HASH(2) at 0x55e14cacb860, which is:
              itself

       (This document isn't intended to be a full tutorial  on  Devel::MAT  and
       the "pmat" shell; for that see Devel::MAT::UserGuide).

       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 could be found - one stored in the
       $ball lexical in the main program, and one stored in a  HASH.  Since  we
       expected  to find the $ball 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 bounce() method.
       Furthermore, we know that the reference to the object will be stored  in
       a HASH in a member called "self".

       By  reading  the  code  which implements the bounce() method, we can see
       this is indeed the case:

          sub bounce
          {
             my $self = shift;
             my $cycle = { self => $self };
             $cycle->{cycle} = $cycle;
          }

       From reading the tracing output, we find that the HASH  this  object  is
       referenced  in  also  contains a reference to itself, in a member called
       "cycle". 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.

       If  "Devel::MAT::Dumper"  is  not  available, then these detailed traces
       will not be produced. The basic reference count testing will still  take
       place, but a smaller message will be produced:

          1..2
          ok 1 - One reference after construct
          not ok 2 - One reference just before EOF
          #   Failed test 'One reference just before EOF'
          #   at demo.pl line 16.
          #   expected 1 references, found 2
          # Looks like you failed 1 test of 2.

BUGS
       •   Temporaries created on the stack

           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

              is_oneref( [] );

           may fail and claim a reference count of 2 instead.

           Passing a variable such as

              my $array = [];
              is_oneref( $array );

           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.

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

AUTHOR
       Paul Evans <leonerd@leonerd.org.uk>

perl v5.40.1                       2026-08-30            Test2:...fcount(3perl)

Generated by dwww version 1.16 on Sat Oct 3 06:47:42 CEST 2026.