The following script creates a window with a menu.
When clicking on the File/Run menu option it will destroy and then recreate
some of the menu items several times (100 by default).
As I can see this script leaks memory.
If I run it as it is it leaks about 20-30 bytes per run.
If I enabled the event generation code as well which is currently
commented out then with each run the RES memory will grow by ~ 600 bytes.
Any idea why is that and how could I avoid?
Do I need to explicitly remove the event handlers? How ?
Gabor
use strict;
use warnings;
my $app = Wx::SimpleApp->new;
my $x = My->new;
$app->MainLoop;
package My;
use strict;
use warnings;
use Params::Util ();
use Wx qw(:everything);
use Wx::Event qw(:everything);
use base qw(Wx::Frame);
sub get_menu {
return [
['First', [qw(A B C)]],
['Second', [qw(D E F)]],
];
}
my $file;
sub new {
my ($class) = @_;
my $self = $class->SUPER::new(
undef, -1, 'Menu', wxDefaultPosition, [ 800, 600 ],
wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE|wxCLIP_CHILDREN );
my $bar = Wx::MenuBar->new;
$file = Wx::Menu->new;
my $add = $file->Append( -1, 'Add' );
my $remove = $file->Append( -1, 'Remove' );
my $run = $file->Append( -1, 'Run' );
$file->Append( wxID_EXIT, '' );
$bar->Append( $file, "&File" );
$self->SetMenuBar( $bar );
$self->refresh;
my $text = Wx::TextCtrl->new
( $self, -1, "", wxDefaultPosition, wxDefaultSize,
wxTE_READONLY|wxTE_MULTILINE|wxNO_FULL_REPAINT_ON_RESIZE );
EVT_MENU( $self, wxID_EXIT, sub { $self->Close } );
EVT_MENU( $self, $add, \&add_entries);
EVT_MENU( $self, $remove, \&remove_entries);
EVT_MENU( $self, $run, \&update_menu);
$self->Show;
return $self;
}
sub update_menu {
my ($self, $event) = @_;
for ( 1..100 ) {
$self->refresh;
}
return;
}
sub add_entries {
my $self = shift;
#print "add\n";
my @entries;
my $menus = $self->get_menu;
foreach my $m (@$menus) {
my $name = $m->[0];
my $menu = $self->create_submenu( $self, $m->[1] );
# print "A: '$name' '$menu'\n";
push @entries, $file->Append( -1, $name, $menu );
}
$self->{entries} = \...@entries;
return 1;
}
sub remove_entries {
my $self = shift;
my $entries = $self->{entries} || [];
while ( @$entries ) {
my $e = pop @$entries;
#print "$e\n";
$file->Destroy( $e );
}
$self->{entires} = $entries;
return 1;
}
sub refresh {
my ($self) = @_;
$self->remove_entries;
$self->add_entries;
}
sub create_submenu {
my $self = shift;
my $main = shift;
my $items = shift;
my $menu = Wx::Menu->new;
foreach my $label ( @$items ) {
#$menu->AppendSeparator;
my $value = sub { print "$label\n"; };
# Wx::Event::EVT_MENU(
# $main,
# $menu->Append( -1, $label ),
# sub {
# eval { $value->(@_) };
# },
# );
}
return $menu;
}