Skip Menu |

This queue is for tickets about the IO-Async CPAN distribution.

Report information
The Basics
Id: 99552
Status: resolved
Priority: 0/
Queue: IO-Async

People
Owner: Nobody in particular
Requestors: leonerd-cpan [...] leonerd.org.uk
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.63
Fixed in: 0.64



Subject: IaFunction ->{workers} never gets cleaned up
Code exists to insert things into the 'workers' hash, but not to remove them again. This is leading to memory leaks. Likely something Devel::MemoryGrowth can easily find. -- Paul Evans
On Fri Oct 17 09:21:50 2014, PEVANS wrote: Show quoted text
> Code exists to insert things into the 'workers' hash, but not to > remove them again. This is leading to memory leaks. > > Likely something Devel::MemoryGrowth can easily find.
Seems not so simple. There is test to remove it in $worker->stop, and that usually happens most of the time. D:MG hasn't found anything from some testing so far. More investigation required -- Paul Evans
Ah; according to Devel::MAT, the Resolver in question has 2273 children but only 5 'workers'. Seems like a missing ->remove_child() call. -- Paul Evans
Patched -- Paul Evans
Subject: rt99552.patch
=== modified file 'lib/IO/Async/Function.pm' --- lib/IO/Async/Function.pm 2014-07-26 19:08:49 +0000 +++ lib/IO/Async/Function.pm 2014-10-17 14:24:46 +0000 @@ -596,6 +596,13 @@ if( my $function = $worker->parent ) { delete $function->{workers}{$worker->id}; + + if( $worker->{busy} ) { + $worker->{remove_on_idle}++; + } + else { + $function->remove_child( $worker ); + } } } @@ -642,6 +649,8 @@ my $function = $worker->parent; $function->_dispatch_pending if $function; + + $function->remove_child( $worker ) if $function and $worker->{remove_on_idle}; })); } === modified file 't/42function.t' --- t/42function.t 2014-01-06 21:10:52 +0000 +++ t/42function.t 2014-10-17 14:24:46 +0000 @@ -8,6 +8,7 @@ use Test::More; use Test::Fatal; use Test::Refcount; +use constant HAVE_TEST_MEMORYGROWTH => eval { require Test::MemoryGrowth; }; use File::Temp qw( tempdir ); use Time::HiRes qw( sleep ); @@ -544,4 +545,25 @@ $loop->remove( $function ); } +# Leak test (RT99552) +if( HAVE_TEST_MEMORYGROWTH ) { + diag( "Performing memory leak test" ); + + my $function = IO::Async::Function->new( + max_workers => 8, + code => sub {}, + ); + + $loop->add( $function ); + + Test::MemoryGrowth::no_growth( sub { + $function->restart; + $function->call( args => [] )->get; + }, calls => 100, + 'IO::Async::Function calls do not leak memory' ); + + $loop->remove( $function ); + undef $function; +} + done_testing;
Released -- Paul Evans