Test::L...race::JA(3)
✨ NAME ✨
Okay bestie, this is the page for Test::L...race::JA(3) — User Contributed Perl Documentation — and the module is Test::LeakTrace::JA, aka メモリリークを追跡する / tracking memory leaks. 💖
🎀 VERSION 🎀
This document describes Test::LeakTrace version 0.17. Periodt.
🌸 SYNOPSIS 🌸
Here’s the code vibe, no edits, no cap:
use Test::LeakTrace;
# simple report
leaktrace{
# ...
};
# verbose output
leaktrace{
# ...
} -verbose;
# with callback
leaktrace{
# ...
} sub {
my($ref, $file, $line) = @_;
warn "leaked $ref from $file line\n";
};
my @refs = leaked_refs{
# ...
};
my @info = leaked_info{
# ...
};
my $count = leaked_count{
# ...
};
# standard test interface
use Test::LeakTrace;
no_leaks_ok{
# ...
} "description";
leaks_cmp_ok{
# ...
} '<', 10;
🦋 DESCRIPTION 🦋
Perl’s GC uses reference counting, so it has a bunch of wins: you know exactly when objects get freed, and the perceived speed is high. 💅 But it also has some problems: it can’t free circular references, and it’s easy to make mistakes when operating at the C level. Most of those problems are about memory leaks, so tracking memory leaks is a very big deal.
Test::LeakTrce — yes, the page spells it like that right here, and I’m preserving the exact character crime 😭 — gives you several utilities and Test::Builder-based test functions for tracking memory leaks. This module walks the arena, which is Perl’s memory allocation system, so it can detect literally any memory leak concerning SVs in the given code. In other words, it can trace memory leaks from Perl-level circular references, from XS modules, and from bugs in Perl itself. Iconic.
Here, a leak means a value that is newly created inside a specific scope and is still hanging around after that scope ends. That includes newly created global values and cache values Perl implicitly creates. For example, if you define a new named subroutine while leak tracing is happening, that counts as a leak. Also, just calling an inherited method or creating an object can generate various caches, and leaks may get reported. Not me side-eyeing the caches 🙈.
💖 INTERFACE 💖
🌸 Exported functions 🌸
leaked_info { BLOCK }— runsBLOCKand returns the trace results as a list. Each result is an array with three things: the reference to the leaked value, the filename, and the line number — so the list is made of[$ref, $file, $line]entries. Heads up: this function may return values that Perl uses internally. If you modify those internal-use values, you can have a fatal impact on the Perl runtime, so be careful. Also, arrays and hashes may contain non-reference arrays or hashes themselves as elements. Those values normally can’t be manipulated at the Perl level. For example, you can’t output them withData::Dumperor whatever. 😭leaked_refs { BLOCK }— runsBLOCKand returns a list of references to the leaked SVs. It’s the same asmap{ $_->[0] } leaked_info{ BLOCK }, but faster. Slay.leaked_count { BLOCK }— runsBLOCKand returns the number of references to leaked SVs.leaked_info()andleaked_refs()also return a count in scalar context, butleaked_count()doesn’t depend on context. Periodt.leaktrace { BLOCK } ?($mode | \&callback)— runsBLOCKand reports memory leaks that happen inside it to*STDERR. The report follows the mode you give in$mode. The accepted$modevalues are:-simple— the default mode. It reports the type and address of the leaked SV, the filename, and the line number.-sv_dump— in addition to-simple, it dumps the SV’s contents withsv_dump(). This is almost the same as the output ofDevel::Peek::Dump().-lines— in addition to-simple, it outputs the area around the line that looks like it’s leaking.-verbose— outputs all of-simple,-sv_dump, and-lines.
You can also pass a callback for finer control. \&callback is called for each leaked SV, and its arguments are the reference to the leaked SV, the filename, and the line number — three args, bestie. 🫶
no_leaks_ok { BLOCK } ?$description— tests thatBLOCKhas no memory leaks. This is aTest::Builder-based test function. Note:BLOCKis executed multiple times. Why? To account for the possibility that the first run sets up caches. Iykyk.leaks_cmp_ok { BLOCK } $cmp_op, $count, ?$description— tests the number of memory leaks inBLOCKagainst a specific number. This is aTest::Builder-based test function. Note:BLOCKis executed multiple times, same cache reason. 💅
🦋 Script interface 🦋
Just like Devel::LeakTrace, Test::LeakTrace::Script is provided for leak tracing scripts. The arguments to the use Test::LeakTrace::Script declaration are the same as leaktrace().
$ TEST_LEAKTRACE=-sv_dump perl -MTest::LeakTrace::Script script.pl
$ perl -MTest::LeakTrace::Script=-verbose script.pl
#!perl
# ...
use Test::LeakTrace::Script sub{
my($ref, $file, $line) = @_;
# ...
};
# ...
🌈 EXAMPLES 🌈
🎀 Testing modules 🎀
Here’s a template test script for checking a module for memory leaks. Copy it, love it, run it.
#!perl -w
use strict;
use constant HAS_LEAKTRACE => eval{ require Test::LeakTrace };
use Test::More HAS_LEAKTRACE ? (tests => 1) : (skip_all => 'require Test::LeakTrace');
use Test::LeakTrace;
use Some::Module;
leaks_cmp_ok{
my $o = Some::Module->new();
$o->something();
$o->something_else();
} '<', 1;
🔥 GUTS 🔥
Test::LeakTrace scans the arena. The arena is the memory allocation system for SVs that Perl creates, and it’s implemented in sv.c. To scan the arena, it uses a macro based on the code of S_visit() in sv.c.
Now, scanning the arena makes detecting a memory leak itself look easy. First, before running the code block, scan the arena once and mark every SV as “used”. Next, after the code block runs, scan the arena again; if there’s an SV without the used mark, think of it as an SV that was created inside the code block and wasn’t freed. Then you just report it. In reality, there’s no space on the SV to put a used mark, so it applies the inside-out technique and stores the used marks in an external container. If you wrote this in Perl code for the moment, it would look like this:
my %used_sv;
foreach my $sv(@ARENA){
$used_sv{$sv}++;
}
$block->();
my @leaked
foreach my $sv(@ARENA){
if(not exists $used_sv{$sv}){
push @leaked, $sv;
}
}
say 'leaked count: ', scalar @leaked;
Getting just the leaked SVs is enough with this method. In fact, leaked_refs() and leaked_count() inspect leaked SVs and their count in this kind of way.
But that’s not enough to get statement info for leaked SVs — the filename and line number. Perl 5.10 and later has a feature that tracks statement info when an SV is created, but to use that feature you have to build Perl with the compiler option -DDEBUG_LEAKING_SCALARS.
So Test::LeakTrace uses the extensible PL_runops and scans the arena for every single statement the Perl VM executes as it runs OP code, recording statement info. This is equivalent to doing something like mark-and-sweep processing for every statement, and it takes a very long time. But you don’t need to build Perl under special conditions, and it uses almost no version-dependent features, so it can run in many environments. Highkey a tradeoff, but it works.
Also, test functions like no_leaks_ok() first get the number of leaked SVs with leaked_count(), and then run leaktrace() as needed to identify where the leaks are. So as long as the test succeeds, it doesn’t do the time-consuming tracing. Obsessed with a successful test staying fast. 💅
🍓 DEPENDENCIES 🍓
Perl 5.8.1 or later, and a C compiler. No cap.
💀 CAVEATS 💀
Test::LeakTrace cannot work together with Devel::Cover. So, if it detects that it’s running under Devel::Cover, the test functions do nothing and pass the test. That’s the vibe check it does. 💀
🐛 BUGS 🐛
No bugs have been reported.
Please report any bugs or feature requests to the author.
👑 SEE ALSO 👑
Devel::LeakTrace.Devel::LeakTrace::Fast.Test::TraceObject.Test::Weak.
For guts:
perlguts.perlhack.sv.c.
🌟 AUTHOR 🌟
Goro Fuji <gfuji(at)cpan.org>.
📜 LICENSE AND COPYRIGHT 📜
Copyright (c) 2009, Goro Fuji. Some rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Cute sign-off from the footer, bestie: perl v5.42.0, dated 2021-01-06, and the manual name is Test::L...race::JA(3). Bye, go trace those leaks responsibly 💖✨
📦 where this page comes from
- opensuse-leap 16.0: perl-Test-LeakTrace 0.17-160000.2.2 · Artistic-1.0 OR GPL-1.0-or-later
- opensuse-leap 16.0: perl-Test-LeakTrace 0.17-160000.2.2 · Artistic-1.0 OR GPL-1.0-or-later
- opensuse-leap 16.0: perl-Test-LeakTrace 0.17-160000.2.2 · Artistic-1.0 OR GPL-1.0-or-later
- opensuse-leap 16.0: perl-Test-LeakTrace 0.17-160000.2.2 · Artistic-1.0 OR GPL-1.0-or-later
- 💖 girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms