saskak has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks!

I built an application in Perl/Tk, but there seems to be some memory problem. The code is a bit longish, but I managed to locate where the problem comes from. Every time I use update on the MainWindow in order to update the ProgressBar, there is a memory build up. So here is a very short Perl/TK application:

use strict; use Tk; use Tk::ProgressBar; my $mw=MainWindow->new; my $percent; my $pb=$mw->ProgressBar( -height => 0, -width => 20, -length => 100, -colors=>[0,'blue'], -blocks=>100, -variable=>\$percent)->pack; my $btn=$mw->Button( -command => \&show_progress, -text => 'Run program', )->pack; MainLoop; sub show_progress{ for (1..100) { $percent=rand(100); $mw->update(); } }

So I was clicking the button on this simple application and was watching the memory usage with the task manager (XP). Every time I click on the button there is memory build up and I just can not figure where this is coming from. It just never goes down.

Click......Memory
1........10,428K
2........10,512K
3........10,576K
4........10,648K
5........10,716K
6........10,780K
7........10,852K
.
etc

I now these are very small increments, but is this some sort of memory leak with the ProgressBar or something else that I am missing here?
This is extremely simple application. When I did a bit more complicated stuff, the memory build up was enormous. A way to overcome this is closing the application every time, but it is a bit annoying. It seems that this is only associated with the ProgressBar widget, not with the update. I tried only update on the ProgressBar widget, but it does not make a difference.

Could you please help me here?
I am using
Perl/Tk 804.027-r6
Perl v5.8.8 MSWin32-x86-multi-thread

Replies are listed 'Best First'.
Re: TK::ProgressBar and update memory build up
by TGI (Parson) on Jun 24, 2008 at 18:16 UTC

    I had the same problem with the same Tk version (which happens to be the ActiveState distributes with ActivePerl 5.8).

    See RT Bug 13400. You could try upgrading to a newer Tk. I simply chose not to use the ProgressBar.


    TGI says moo

Re: TK::ProgressBar and update memory build up
by psini (Deacon) on Jun 24, 2008 at 18:19 UTC

    Commenting out the last line (#$mw->update();) I found that the program runs as before (update is not needed) and there is no more memory leak.

    The strange thing is that the same effect (no leak) can be obtained commenting out the $percent=rand(100); line instead of the update line.

    In this last version I occasionally get this message in console:

    Tk::Error: Usage $widget->update(...) MainWindow=HASH(0x8286464) is not a Tk object at ./x.pl line 28. Tk callback for .button <ButtonRelease-1> (command bound to event)

    IMHO this seems to imply that the update method is not fully reentrant and so repeated calls to it may cause a problem. I don't know if this can be related to the memory leak problem that looks like a var reference not correctly freed...

    Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."

Re: TK::ProgressBar and update memory build up
by psini (Deacon) on Jun 24, 2008 at 18:03 UTC

    I tested your code on my Linux box (Debian Sarge Etch) and I detected the same problem: about 40 KByte of overhead every click.

    Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."

      10x, the problem is when using the ProgressBar in more complicated application and the build up is much more. It just eats memory. Maybe I should build my own progressbar and see whether it will help.
Re: TK::ProgressBar and update memory build up
by saskak (Novice) on Jun 24, 2008 at 22:44 UTC
    Thanks TGI, it seems that there is indeed a memory leak and it is a bug related to my ver of TK. When I tested the app in RT Bug 13400, it was leaking.
    I installed the newest TK (804.028) and it seems that the bug has been fixed.

    Thanks psini for pointing out that repeated calls to update method could cause problems. In fact I was using the update method quite a lot and hence a lot of memory leakage.

    I am new to Perl/Tk, but the only method I saw for update/refresh of a progress bar was with the update method. The binding of the progress bar to a variable and subsequently changing the variable in a subroutine does not automatically update the progress bar. The update is in the MainLoop
    I am just out of ideas how to update/refresh a progress bar when I am doing something else and show how much progress is being made.
Re: TK::ProgressBar and update memory build up
by zentara (Cardinal) on Jun 25, 2008 at 11:26 UTC
    Yeah the Progressbar has repeated use issues. One way is to use the value method, this dosn't leak for me on linux after repeated clicks, but may leak if run from a timer. .
    #!/usr/bin/perl use strict; use Tk; use Tk::ProgressBar; my $mw=MainWindow->new; my $percent; my $pb=$mw->ProgressBar( -height => 0, -width => 20, -length => 100, -colors=>[0,'blue'], -blocks=>100, )->pack; my $btn=$mw->Button( -command => \&show_progress, -text => 'Run program', )->pack; MainLoop; sub show_progress{ for (1..100) { $percent=rand(100); $pb->value($percent); } }
    If you absolutely need alot of updates, and need to avoid memory gains, you can roll your own with a label. You can get the width right by playing around. No leaks at all on linux.
    #!/usr/bin/perl use strict; use Tk; my $mw=MainWindow->new; my $percent; my $pb= $mw->Label( -bg => 'white', -fg => 'blue', -width => 60, -justify => 'left', -anchor => 'w', )->pack(); my $label1 = $mw->Label( -textvariable=> \$percent, )->pack(); my $timer = $mw->repeat(10,\&show_progress); MainLoop; sub show_progress{ $percent += 1; if($percent >= 100){$percent = 0} my $str = '|' x $percent; $pb->configure(-text => $str ); }

    I'm not really a human, but I play one on earth CandyGram for Mongo
Re: TK::ProgressBar and update memory build up
by saskak (Novice) on Jun 25, 2008 at 21:56 UTC
    Thank you all, for the help.
    I think I have a revelation. My initial Perl/Tk application was to open a file, read it, do some calculations on the data and then write a new file.
    There are a few parameters that one can choose in the application and I was thinking of changing a few parameters and run the same application without closing it. Then again, there was quite a big memory build up.
    Initially I thought that the memory leak was coming from the ProgressBar or the update method I was using. When I upgraded the Tk ver, the memory leak associated with the ProgressBar dissapeared, but the memory build up in my application stayed pretty much the same.

    I managed to trace it down, and it is coming from the reading of the file itself.
    Here is a example application:
    #!/usr/bin/perl use strict; use warnings; use Tk::Carp qw/fatalsToDialog/; use Tk::Carp qw/warningsToDialog/; use Tk; my ( $in_file_name, $out_file_name, $MW, $message, $count_runs ); $MW = MainWindow->new(-title=>"Open/read times"); my $Frame=$MW->Labelframe( -text => 'Input Parameters', )->pack(); my $Ent_In_File_Name=$Frame->Entry( -textvariable => \$in_file_name, )->grid( -row => 0, -column => 0, -sticky => 'w', ); my $Btn_Open_File=$Frame->Button( -command => 'main::open_file', -text => 'Open File', )->grid( -row => 0, -column => 1, -sticky => 'w', ); my $Btn_run=$Frame->Button( -command => 'main::run_program', -text => 'Run program', )->grid( -row => 3, -column => 0, -sticky => 'w', ); my $Ent_Run=$Frame->Entry( )->grid( -row => 3, -column => 1, -sticky => 'w', ); ###### SUBROUTINES ################################################### +########## sub open_file { my $file_name_open=$MW->getOpenFile(); $Ent_In_File_Name->delete(0,'end'); $Ent_In_File_Name->insert(0,$file_name_open); } sub run_program { $count_runs++; my @data; open MYFILE ,$in_file_name or die "Could not open file to read:$in +_file_name\n"; while(<MYFILE>) { my $temp=$_; chomp $temp; my @array=split("\t",$temp); push(@data,[@array]); } close MYFILE; $Ent_Run->delete(0,'end'); $Ent_Run->Insert("open/read N:$count_runs"); } MainLoop();

    The file is a Tab delimeted text file (~15Mb).
    The strange thing is that every time I run this simple thing (Hit Run program button without closing the application), there is a memory leak of about 700-800Kb.
    I tried the same thing with a simple perl script:
    #!/usr/bin/perl use warnings; use strict; my $in_file="\\in_file\.txt"; my $count_runs=0; while (1) { $count_runs++; my @data; open MYFILE ,$in_file or die "Could not open file to read:$in_file +\n"; while(<MYFILE>) { my $temp=$_; chomp $temp; my @array=split("\t",$temp); push(@data,[@array]); } close MYFILE; print "run $count_runs\n"; <>; }
    The result, no leak at all.
    I am quite surprised here. Should'nt the local vars declared with my be cleared when it goes out of scope???
    It seems that this is only associated with Tk, but not Perl itself.
    I just donot know what is going on here.
    Any help would be appreciated. It is just bizzare.
Re: TK::ProgressBar and update memory build up
by saskak (Novice) on Jun 26, 2008 at 08:38 UTC
    An update to my last post. The pure perl script isnot quite correct. Should have called a sub to read the file like this:
    #!/usr/bin/perl use warnings; use strict; my $in_file="\\in_dile\.txt"; my $count_runs=0; while (1) { $count_runs++; read_file(); print "run $count_runs\n"; <>; } sub read_file { my @data; open MYFILE ,$in_file or die "Could not open file to read:$in_file +\n"; while(<MYFILE>) { my $temp=$_; chomp $temp; my @array=split("\t",$temp); push(@data,[@array]); } close MYFILE; }

    An like in the Perl/TK app, the memory leak is there. Maybe I am doing something wrong with the anonymous array. But again, should the local vars be cleared when going out of scope in every call to the sub.
Re: TK::ProgressBar and update memory build up
by saskak (Novice) on Jun 26, 2008 at 11:27 UTC
    SH!T. It seems there is no problem anywhere in the code. I just browsed through my tab delimited text file. There are tab delimited entries of length 26000 characters. When I removed them, then there is no memory build up.
    Somehow an entry in an array of size 26000 characters messes up the memory somehow.

    Anyhow, thanks everyone.