tkinter/tk memory questions

Edward K. Ream edream at tds.net
Tue Dec 3 21:07:12 EST 2002


I am posting this to comp.lang.python and comp.lang.tcl because this posting
concerns Python(tkinter) and tcl/tk.

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.

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.

I'm wondering whether this is something to be concerned about, and if so,
what to do about it.  Note that expanding and contracting the outline is not
undoable, and causes no memory to be allocated for undo/redo.

Here is what I have done:

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)

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 :-)

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:

# When creating bindings:
self.canvas.tag_bind(id, "<1>", v.OnBoxClick)
t.bind("<1>", v.OnHeadlineClick)
if self.recycleBindings:
  self.tagBindings.append((id,"<1>"),)
  self.bindings.append((t,"<1>"),)

# When redrawing the screen:
self.deleteBindings()
self.canvas.delete("all")

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.

So my questions are:

- Am I correct in my assumption that the memory being used is being used by
tcl?
- Is this a problem at all?  Will tcl eventually get around to freeing
memory?  And how would I know?
- 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?
- 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?

Thanks.

Edward
--------------------------------------------------------------------
Edward K. Ream   email:  edream at tds.net
Leo: Literate Editor with Outlines
Leo: http://personalpages.tds.net/~edream/front.html
--------------------------------------------------------------------





More information about the Python-list mailing list