in reply to Tk, HLists and memory leakage

Is there an reasonable way to see what data aren't being garbage collected?

What I do is place Data::Dumper statements at critical points in the program, and watch for the variables growing....like extra hash keys.

If I really need to rethink my wanton creation and destruction of widgets, can anyone suggest some strategies for keeping a pool of widgets around and configuring them as needed?

I think you answered your own question. Hlist entries can be reconfigured, so don't delete and create new ones.

You usually do this, by separating your actual data storage, from the displaying of the data. In other words, don't use the widget to store your data, use the widget to display data stored in another hash. That way the widgets are just a "window to the screen" to display what is in some underlying data hash. They remain the same, just being reconfigured to display the new data.

Here are a few examples.

#!/usr/bin/perl use strict; use Tk; use Tk::HList; my $mw = MainWindow->new(); my $label = $mw->Label( -width => 15 ); my $hlist = $mw->Scrolled('HList', -itemtype => 'text', -selectmode => 'single', )->pack; foreach (1..1000) { my $text = $_.time; $hlist->add( $_, -text => $text ); } my $button = $mw->Button(-text => 'Leak Test', -command => \&testleak)->pack; MainLoop; sub testleak{ #foreach (1..1000) { # # $hlist->delete('all'); # $hlist->delete('entry',$_); # } foreach (1..1000) { my $text = $_.time; # $hlist->add( $_, -text => $text ); $hlist->entryconfigure( $_, -text => $text ); } }
#!/usr/bin/perl use strict; use Tk; use Tk::HList; my $mw = MainWindow->new(); #create some sample data my %data; foreach (0..100) { $data{$_}{'name'} = 'name'.$_; $data{$_}{'id'} = rand(time); $data{$_}{'priority'} = int rand 50; } #get random list of keys my @keys = keys %data; ################# my $h = $mw->Scrolled( 'HList', -header => 1, -columns => 3, -width => 40, -height => 40, -takefocus => 1, -background => 'steelblue', -foreground =>'snow', -selectmode => 'single', -selectforeground => 'pink', -selectbackground => 'black', # -browsecmd => \&browseThis, )->pack(-side => "left", -anchor => "n"); $h->header('create', 0, -text => ' Name ', -borderwidth => 3, -headerbackground => 'steelblue', -relief => 'raised'); $h->header('create', 1, -text => ' ID ', -borderwidth => 3, -headerbackground => 'lightsteelblue', -relief => 'raised'); $h->header('create', 2, -text => ' Priority ', -borderwidth => 3, -headerbackground => 'lightgreen', -relief => 'raised'); foreach (@keys) { my $e = $h->addchild(""); #will add at end $h->itemCreate ($e, 0, -itemtype => 'text', -text => $data{$_}{'name'}, ); $h->itemCreate($e, 1, -itemtype => 'text', -text => $data{$_}{'id'}, ); $h->itemCreate($e, 2, -itemtype => 'text', -text => $data{$_}{'priority'}, ); } my $button = $mw->Button(-text => 'exit', -command => sub{exit})->pack; my $sortid = $mw->Button(-text => 'Sort by Id', -command => [\&sort_me,1] )->pack; my $sortpriority = $mw->Button(-text => 'Sort by Priority', -command => [\&sort_me,2] )->pack; MainLoop; ######################################################### sub sort_me{ my $col = shift; my @entries = $h->info('children'); my @to_be_sorted =(); foreach my $entry(@entries){ push @to_be_sorted, [ $h->itemCget($entry,0,'text'), $h->itemCget($entry,1,'text'), $h->itemCget($entry,2,'text'), ]; } my @sorted = sort{ $a->[$col] cmp $b->[$col] || #primary sort ascii + $a->[1] <=> $b->[1] #secondary sort num +eric } @to_be_sorted; my $entry = 0; foreach my $aref (@sorted){ # print $aref->[0],' ',$aref->[1],' ',$aref->[1],"\n"; $h->itemConfigure( $entry, 0, 'text' => $aref->[0] ); $h->itemConfigure( $entry, 1, 'text' => $aref->[1] ); $h->itemConfigure( $entry, 2, 'text' => $aref->[2] ); $entry++; } $mw->update; }

I'm not really a human, but I play one on earth. flash japh

Replies are listed 'Best First'.
Re^2: Tk, HLists and memory leakage
by TGI (Parson) on Oct 20, 2005 at 18:50 UTC

    Your suggestion of separating the data storage from the widget is what I am doing already--unless you are suggesting that instead of pointing my widgets at values in an object instance that is dedicated to the widgets, I should be creating a separate hash. I don't see how that could help. My description of the issues must have been unclear.

    I don't see the leakage when I use items of type text. The problem comes up with items of type 'window' or 'widget'. Memory seems to be reclaimed when I create and destroy text items.

    As to using Data::Dumper, which values do I dump? I have already explicity destroyed my widgets, so I can't dump them. Dumping the MainWindow shows me nothing useful, same with the HList widget. What should I be dumping? What I'd really like to see is a memory map with each stored value and a set of reference counts for each.

    Keeping items around and then configuring is fine if you have a static, well defined number of items you want to display. In my case, a rule may have one or 100 clauses. Creating and managing a pool of identical HList entries seems to be a hassle. Add to this the fact that I need to be able to change which widget is displayed in a given item, based on the values selected in other widgets (eg Field_1 has a list of legal values, but Field_2 can be any integer, so I use a menu and an entry, respectively, to handle input). Should I then pre-create entries with each possible set of widgets to meet my needs?

    I could reduce the size of a precaching implementation by allocating a bank of each type of widget: HList items, Optionmenus, Entries, and Checkbuttons. Then I would need to track which ones were active, and which ones weren't, and probably handle making more as needed. Then available widgets could be assinged to available items in available entries. If I have to do all that, what benefit does the HList really offer over rolling my own similar functionality using a Frame and grid()? I chose the HList widget because it looked like should handle many of these issues for me. I am beginning to this this was a mistake.


    TGI says moo

      First, it will always be unclear to me what you are doing, because I'm not writing your app, and my head just isn't into what you are doing. All I can do is relate my similar experiences with HLists and mem leaks.

      As far as what widgets or hashes to dump, it is kind of an "art" to figure out where and what to dump. Try linux memory leak monitor and carefully watch what happens on each click of your app. You should be able to deduce which subs are being called when you see memory jumps, then dump all hashes involved. You can also use Devel::Size to get an idea of the size of the variables.

      As far as dealing with 1 or 100 clauses, and keeping a static number of widgets; you can do it. Just keep track of each widget-set you create for each clause, and store it all in a hash. If you don't need it, don't destroy it, just unpack it, and it will be there for future re-use. I know it sounds like a hassle to track and store all created widgets, unpacking, reconfiguring and repacking them as needed, but that is what you will have to do if you want to manage your memory and keep it from the constant upward increase.

      And of course, like you said, maybe the HList isn't the right widget for you, if your entries don't all use the same widgets. Maybe you could devise a few different Hlist's, each configured to display a different set of widgets, and call that HList model depending on your display needs. Maybe Tk::TableMatrix would better suit your needs?


      I'm not really a human, but I play one on earth. flash japh

        I am sorry if I sounded upset with you in my replies. I'm frustrated, and that probably came out in my tone. I didn't intend to be rude, especially not to someone who is trying to help. If I was impolite, or rude, or wrote inappropriately, I am truly sorry. It was not my intent to be rude and I hope you will accept my apology.

        Sadly, I am forced to develop on and for Windows, so I can't use the memory leak monitor. Platform issues notwithdstanding, it looks like it would be handy. I might be able to find a way to tweak it for windows. If I do, I'll post a reply to that node.

        Part of the problem is that I need to have a lot of dynamism in which widgets are displayed.

        To try to better explain what I'm doing, I'll break it down into smaller pieces--it may help to refer to the ASCII art in my OP. I need to display a list of clauses and allow the user to edit them. The interface is much like the one used by thunderbird to create mail filters. Each clause consists of a field name, an operator, and a value. Different fields have different lists of legal operators. Different fields also have different rules about what values are acceptable. For example, we have several temperature fields which have any number for their values; I use an entry for value entry. We also have a Wet/Dry field that can be only "Wet or Trace" or "Dry"; I use an option menu. If the user changes the field from TEMP to WD, then the value widget must be changed from an Entry to an Optionmenu and the operator Optionmenu must be changed to display the correct list or operations (you can't very well check to see if something is "less than or equal to" Wet). It's also worth noting that I may be working with any number of clauses, and I need to able to add or delete them as needed.

        I hade hoped to handle all this dynamism by creating and destroying the involved widgets and HList entries as needed. It looks like I can't do anything to cleanly expungethe widgets and entries though--even if I explicitly destroy my widgets, destroy my objects and delete my entries.

        So, to implement a cached-entry approach to my problem, I'll need to create a set of HList items that have the different possible widgets. When the user changes the field value, I will need to decide if I need to hide the current Hlist entry, uncouple it from my Clause object and configure an HList entry with the correct widget set to display the clause. Is that correct?

        I'll take a look at the TableMatrix widget. Thank you for the suggestions.


        TGI says moo