How to find memory leaks in Perl script?
Question
How to find memory leaks in Perl script?
Detecting memory leaks in Perl often revolves around understanding circular references and how Perl's reference counting garbage collector works. A circular reference happens when two or more references keep pointing to each other, preventing their reference counts from ever dropping to zero, thus causing memory not to be freed.
Perl's core module Scalar::Util provides useful tools like weaken to break circular references by making some references "weak," meaning they don't increase the reference count.
Common Causes of Memory Leaks in Perl
- Circular references: Objects referencing each other indefinitely.
- Global or package variables: Holding references beyond intended scope.
- Closures capturing variables: Sometimes leading to cycles.
Example: Detect and Fix Circular Reference Using Scalar::Util::weaken
The following example creates two objects that reference each other, causing a circular reference. We then demonstrate how to break the cycle using a weak reference so Perl can properly destruct the objects and free memory.
use strict;
use warnings;
use Scalar::Util qw(weaken);
{
package Node;
sub new {
my ($class, $name) = @_;
return bless { name => $name, child => undef }, $class;
}
sub add_child {
my ($self, $child) = @_;
$self->{child} = $child;
}
sub DESTROY {
my $self = shift;
print "Destroying Node $self->{name}\n";
}
}
# Create two nodes with a circular reference
my $node1 = Node->new("A");
my $node2 = Node->new("B");
$node1->add_child($node2);
$node2->add_child($node1); # Circular ref here
print "Created circular reference between node1 and node2\n";
# Try to free both
undef $node1;
undef $node2;
print "If DESTROY not called above, circular refs caused memory leak.\n\n";
# Fix circular reference with weaken
{
my $n1 = Node->new("X");
my $n2 = Node->new("Y");
$n1->add_child($n2);
# Weaken the back reference to break cycle
weaken($n2->{child} = $n1);
print "Created circular reference but with weaken on n2->{child}\n";
undef $n1;
undef $n2;
print "DESTROY called because circular ref broken by weaken\n";
}
Explanation
Scalar::Util::weakenmakes one of the references "weak," so it doesn't increase the reference count.- Without weakening, circular references keep objects alive indefinitely;
DESTROYis never called. - With weakening, when the last strong reference goes away, the objects are properly cleaned up.
- This example uses a
Nodepackage with aDESTROYmethod to demonstrate when objects are freed.
Common Pitfalls
- Attempting to inspect reference counts with
refcountrequires newer Perl versions and is not always reliable. - Forgetting to weaken one side of circular references in complex data structures.
- Relaying solely on OS memory usage stats which can fluctuate due to Perl’s internal memory management.
In summary, the core approach to find and fix leaks in Perl is to identify circular references and break them with Scalar::Util::weaken. This method works reliably on Perl 5.8 and later without external modules, keeping your code safe and leak-free.
Verified Code
Executed in a sandbox to capture real output. • v5.34.1 • 20ms
Created circular reference between node1 and node2
If DESTROY not called above, circular refs caused memory leak.
Created circular reference but with weaken on n2->{child}
Destroying Node X
Destroying Node Y
DESTROY called because circular ref broken by weaken
Destroying Node B
Destroying Node A
(empty)