tkinter/tk memory questions

Jeffrey Hobbs JeffH at ActiveState.com
Wed Dec 4 03:52:05 EST 2002


Edward K. Ream wrote:
> I am posting this to comp.lang.python and comp.lang.tcl because this posting
> concerns Python(tkinter) and tcl/tk.

I only saw this not clt, so I added clp

> My Python/tkinter app creates an outline using Tk.Text widgets embedded in a
> Tk.Canvas, using the Idle tree code as a starting point.

I could think of more efficient ways to create an outline, but that isn't
the point of this post ...

> On XP, expanding and contracting the outline causes memory allocated to my
> app (as reported by the XP task manager) to increase significantly, say 4
> meg per expansion.  Contraction might be expected to recycle bindings
> (bindings are allocated only for visible nodes) but does not.

Does this continue to grow with repeated expansion/contraction of the
same outline node?  If not, all you are seeing is an aspect of Tcl's
internal mem allocator, which is (was) high-water mark based.  I saw was,
because in newer versions of Tcl (at least 8.3.4, but likely earlier, I
can't remember when I switched it) it uses the system malloc directly on
Windows, which means it should free large chunks back to the OS.

If you do see continued growth, then there is a leak of some sort somewhere,
but it could be in Tk, Tcl or Python, and not necessarily the C parts (it
could be structures not cleaned up at the language level).

> 1. When expanding or contracting the outline (or for that matter, making
> _any_ change to outline) my app calls self.canvas.delete("all"), just as
> Idle does, before completely redrawing the canvas. I would naively think
> that this would "recycle" all the bindings made via bind and tag_bind in the
> canvas, except for a comment in the TreeNode.draw method in TreeWidget.py,
> viz.,
> 
> # XXX This leaks bindings until canvas is deleted:
> self.canvas.tag_bind(id, "<1>", callback)
> self.canvas.tag_bind(id, "<Double-1>", lambda x: None)

What do you mean by "leaks bindings"?  You created separate bindings, so
it should maintain any binding until set to empty or the canvas goes away.

> 2. Calling gc.collect() has no effect, regardless of what I do.  Moreover,
> gc.garbage (with gc tracing on) shows no garbage accumulating as the result
> of expanding or contracting outlines.
> 
> It appears to me, therefore, that Tk (or tkinter?) is not immediately
> recycling the memory used for bindings.  I'm not sure that tcl is entitled
> to merely because I call self.canvas.delete("all"), but that is what I was
> hoping for :-)

Re: delete all, it depends on the id.  You can create bindings to to tags
that are symbolic, which means that you can delete all items, and create
them with -tags set to the symbolic name and they get those bindings again.
Here is an example in Tcl:

(hobbs) 50 % pack [canvas .c]
(hobbs) 51 % .c create rect 30 30 80 80 -fill blue -tags foo
1
(hobbs) 52 % .c bind foo <Enter> { puts foo }
	[Go to window and enter the square]
foo
(hobbs) 53 % .c delete all
(hobbs) 54 % .c create rect 40 40 70 70 -fill green -tags foo
2
	[Go to window and enter the square]
foo

> 3. In an effort to "encourage" Tk to do some recycling I tried to record all
> the bindings made while drawing the outline.  Something like this:
	...
> def deleteBindings (self):
>  for id,binding in self.tagBindings:
>   self.canvas.tag_unbind(id,binding)
>  self.tagBindings = []
>  for t,binding in self.bindings:
>   t.bind(binding,"")
>  self.bindings = []
> 
> But this has no apparent affect (for good or ill).  Note that 12,000 or more
> bindings may be unbound by deleteBindings when contracting a large outline.

Hmmm, that doesn't mem related to the bindings?  It should on the Tk side.
However, see note above about high-water mark allocator.

> - Am I correct in my assumption that the memory being used is being used by
> tcl?

Possibly.

> - Is this a problem at all?  Will tcl eventually get around to freeing
> memory?  And how would I know?

It should.  Tcl has been thoroughly leak-tested.  Tk hasn't been thoroughly
leak-tested, but it has had the rough comb of approval.

> - Does tcl use a gc?  If so, is there a way to force to collect explicitly?
> And if so, is it a good idea to do so?

No, it uses refcounts internally.  Doing things like setting a binding to
"" should free the memory though.

> - Are there any mechanisms in tkinter that might be helpful?
> - I'm pretty careful not to create any permanent references to bindings.
> Might tkinter be doing that?
> - Is there any way to force Tk to recycle memory used by bindings?
> - Is there anything clearly wrong about what I am doing?
> - Can anyone explain the comment in Idle about leaking bindings?
> - Is there anything else I should know or do?

The rest are more Tkinter questions that I can't answer ...

-- 
     Jeff Hobbs                     The Tcl Guy
     Senior Developer               http://www.ActiveState.com/
         Tcl Support and Productivity Solutions




More information about the Python-list mailing list