in reply to Re^10: Detecting memory leaks.
in thread Detecting memory leaks.

Umm

I think something went wrong , things seem different from what I remember and from what it apparently is, I'm unsure of stuff now

Consider this program

#!/usr/bin/perl -- use strict; use warnings; use Wx; use Devel::Leak; use Scalar::Util;; Main( @ARGV ); exit( 0 ); sub Main { my $app = Wx::SimpleApp->new; my $frame = Wx::Frame->new( undef, -1, "", ); $frame->SetBackgroundColour( Wx::wxBLACK() ); $frame->SetSizer( Wx::BoxSizer->new( Wx::wxVERTICAL() ) ); my $text = Wx::TextCtrl->new( $frame, -1, join( ' ', "\n", Perl => $], Wx => $Wx::VERSION, Wx::wxVERSION +_STRING, "\n" ), [ -1, -1 ], [ -1, -1 ], Wx::wxTE_MULTILINE() ); my $b1 = Wx::Button->new( $frame , -1, "new f new p", ); my $b2 = Wx::Button->new( $frame , -1, "new f child p", ); my $b3 = Wx::Button->new( $frame , -1, "new f child p destroy", ); my $b4 = Wx::Button->new( $frame , -1, "new f weaken child p destr +oy", ); my $b5 = Wx::Button->new( $frame , -1, "new f weaken circle child +p destroy", ); Wx::Event::EVT_BUTTON( $frame, $b1, sub {my $count1 = Devel::Leak +::NoteSV(my $handle); for(1..100){ Wx::Panel->new ; Wx::Frame->new( $ +frame ,-1,"goner" ); } my $count2 = Devel::Leak::CheckSV($handle); $ +text->AppendText( join '', "Count1 = '",$count1,"'\n", "Count2 = '",$ +count2,"'\n", "Diff = '",$count2-$count1,"'\n" ); $text->AppendText( +psmem('new f new p') ); } ); Wx::Event::EVT_BUTTON( $frame, $b2, sub {my $count1 = Devel::Leak +::NoteSV(my $handle); for(1..100){ Wx::Panel->new( Wx::Frame->new( $f +rame ,-1,"goner" ) ); } my $count2 = Devel::Leak::CheckSV($handle); + $text->AppendText( join '', "Count1 = '",$count1,"'\n", "Count2 = '" +,$count2,"'\n", "Diff = '",$count2-$count1,"'\n" ); $text->AppendText +( psmem('new f child p') ); } ); Wx::Event::EVT_BUTTON( $frame, $b3, sub {my $count1 = Devel::Leak +::NoteSV(my $handle); for(1..100){ my $f = Wx::Frame->new( $frame ,-1 +,"goner" ) ; Wx::Panel->new( $f )->Destroy; $f->Destroy; } my $count +2 = Devel::Leak::CheckSV($handle); $text->AppendText( join '', "Coun +t1 = '",$count1,"'\n", "Count2 = '",$count2,"'\n", "Diff = '",$count2 +-$count1,"'\n" ); $text->AppendText( psmem('new f child p destroy') ) +; } ); Wx::Event::EVT_BUTTON( $frame, $b4, sub {my $count1 = Devel::Leak +::NoteSV(my $handle); for(1..100){ my $f = Wx::Frame->new( ($frame ), +-1,"goner" ); my $p = Wx::Panel->new( Scalar::Util::weaken($f) ); $p +->Destroy; $f->Destroy; undef $p; undef $f; } my $count2 = Devel::L +eak::CheckSV($handle); $text->AppendText( join '', "Count1 = '",$coun +t1,"'\n", "Count2 = '",$count2,"'\n", "Diff = '",$count2-$count1,"'\n +" ); $text->AppendText( psmem('new f weaken child p destroy') ); } ); Wx::Event::EVT_BUTTON( $frame, $b5, sub {my $count1 = Devel::Leak +::NoteSV(my $handle); for(1..100){ my $f = Wx::Frame->new( ($frame ), +-1,"goner" ); my $p = Wx::Panel->new( Scalar::Util::weaken($f) ); $f +->{p}=Scalar::Util::weaken($p); $p->Destroy; $f->Destroy; undef $p; +undef $f; } my $count2 = Devel::Leak::CheckSV($handle); $text->Appen +dText( join '', "Count1 = '",$count1,"'\n", "Count2 = '",$count2,"'\n +", "Diff = '",$count2-$count1,"'\n" ); $text->AppendText( psmem('new +f weaken circle child p destroy') ); } ); $frame->GetSizer->Add( $text, 1, Wx::wxEXPAND() ); $frame->GetSizer->Add( $_, 0,0 ) for $b1, $b2, $b3, $b4, $b5; $frame->Show(1); $app->SetTopWindow( $frame ); $text->AppendText( psmem('MainLoop') ); $app->MainLoop; } sub psmem { my ( $msg ) = @_; my @lines = qx{pslist -m $$ 2>NUL}; ## http://live.sysintern +als.com/pslist.exe shift @lines for 1..3; chomp @lines; #~ print join "\n", @lines, ""; #~ Name Pid VM WS Priv Priv Pk Faults +NonP Page #~ perl 1052 25348 7220 4504 4512 1977 + 2 33 my %ps; @ps{'Name', 'Pid', 'VM', 'WS', 'Priv', 'Priv Pk', 'Faults', 'NonP', 'Page' } = grep length, split /\s+/, shift @lines; #~ Pri Priority #~ Thd Number of Threads #~ Hnd Number of Handles #~ VM Virtual Memory #~ WS Working Set ------ "Mem Usage" in taskmanager #~ Priv Private Virtual Memory ------ "VM Size" in taskman +ager #~ Priv Pk Private Virtual Memory Peak #~ Faults Page Faults #~ NonP Non-Paged Pool #~ Page Paged Pool #~ Cswtch Context Switches #~ use DDS; Dump(\@lines , \%ps); #~ print "VM: $ps{VM} RSS: $ps{WS} - $msg\n"; return "VM: $ps{VM} < WS: $ps{WS} VM: $ps{Priv} > $msg\n"; + } __END__ Perl 5.016001 Wx 0.9922 wxWidgets 2.9.4 VM: 53420 < WS: 21900 VM: 19624 > MainLoop Count1 = '34745' Count2 = '35050' Diff = '305' VM: 53420 < WS: 23084 VM: 20632 > new f weaken circle child p des +troy Count1 = '34750' Count2 = '35050' Diff = '300' VM: 53420 < WS: 23088 VM: 20632 > new f weaken circle child p des +troy Count1 = '34750' Count2 = '35050' Diff = '300' VM: 53420 < WS: 23088 VM: 20632 > new f weaken circle child p des +troy Count1 = '34750' Count2 = '34950' Diff = '200' VM: 53420 < WS: 23088 VM: 20632 > new f weaken child p destroy Count1 = '34750' Count2 = '34950' Diff = '200' VM: 53420 < WS: 23100 VM: 20640 > new f child p destroy Count1 = '34750' Count2 = '35150' Diff = '400' VM: 53420 < WS: 23220 VM: 20728 > new f child p Count1 = '35150' Count2 = '35550' Diff = '400' VM: 53420 < WS: 23444 VM: 20924 > new f new p Count1 = '35550' Count2 = '35950' Diff = '400' VM: 53420 < WS: 23664 VM: 21120 > new f new p Count1 = '35950' Count2 = '36350' Diff = '400' VM: 53420 < WS: 23880 VM: 21316 > new f new p

"new f new p" is not supposed to leak 400 scalars

"new f child p" is not supposed to leak 400 scalars because the reference is supposed to be a weak reference

"new f child p destroy" is not supposed to leak 200 scalars, circular reference or no circular reference, Destroy is supposed to clean them all up

...

So maybe this is just taskmanager lying to me, or Devel::Cycle lying, or I'm really mis remember how this used to work or how its supposed to work, but I'm pretty sure this is a bug that needs to be reported to rt://Wx :) you should report it

Heck, consider these oneliners

perl -MWx -e"sub Wx::Frame::DESTROY { $_[0]->Destroy; } for(1..4){for( +1..2000){ my $f =Wx::Frame->new; } scalar<>;}" perl -MWx -e"for(1..4){for(1..2000){ my $f =Wx::Frame->new; } scalar<> +;}" perl -MWx -e"for(1..4){for(1..2000){ my $f =Wx::Frame->new; $f->Close; + } scalar<>;}" perl -MWx -e"for(1..4){for(1..2000){ my $f =Wx::Frame->new; $f->Close; + undef $f; } scalar<>;}" perl -MWx -e"for(1..4){for(1..2000){ my $f =Wx::Frame->new; $f->Close; + $f->Destroy; undef $f; } scalar<>;}"

My winxp taskmanager tells me memory keeps increasing with these programs ... well its pretty much not supposed to

Dang

Replies are listed 'Best First'.
Re^12: Detecting memory leaks.
by Steve_BZ (Chaplain) on May 11, 2015 at 16:09 UTC

    Hi Anon,

    I posted on the Wx::Perl Mailing list and got this reply:

    See http://docs.wxwidgets.org/3.0/classwx_window.html#a6bf0c5be864544d9ce0560087667b7fc details for wxWindow::Destroy.

    As you have determined, top level windows you create need to be destroyed with $win->Destroy;

    The C++ structure for a Wx::Frame contains a reference to the associated Perl SV. So that SV won't go away until the C++ structure is deleted - which will never happen until your event loop is running.

    Regards

    Steve

      That is easy to say, but there is no code to prove it

      I posted Re^11: Detecting memory leaks. because it disproves that theory, event loop is running, memory is growing

      Here is $app->Dispatch which is running the event loop manually one event at a time , this should clean up the memory but it doesn't

      update: it finally does, solution is to pair $window->Destroy; Wx::wxTheApp()->ProcessIdle; don't know at what point in wxwidgets history ProcessIdle became required/necessary for memory reclamation, I don't remember needing to do that explicitly, but it seems it has, werid but a solution is a solution :)

      *whew* sanity restored

      #!/usr/bin/perl -- use strict; use warnings; use Wx; my$app=Wx::SimpleApp->new; for(1..10){ for(1..2000){ my $f =Wx::Frame->new; $f->Close; $f->Destroy; undef $f; $app->ProcessIdle; ## CRITICAL ## can also be written as ## Wx::wxTheApp()->ProcessIdle; #~ $app->Dispatch for 1..1000; $app->Dispatch for 1..10; } scalar<>; } __END__

        Hi Anon,

        I actually did $app->Yield, which I guess is similiar to $app->ProcessIdle;,

        However, the key thing was we've now run 90 video tests with no crashes!!

        Thanks a lot for your help, it was nice to know that I wasn't alone. And it was you who directed me to post a bug, which was what brought out this resolution.

        Regards

        Steve.

Re^12: Detecting memory leaks.
by Steve_BZ (Chaplain) on May 09, 2015 at 20:16 UTC

    Thanks anon, I will investigate further and then report.

    I'll let you know what happens.