Patches item #1524639, was opened at 2006-07-18 17:00
Message generated for change (Comment added) made by grahamh
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1524639&group_id=5470

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Tkinter
Group: Python 2.5
Status: Open
Resolution: None
Priority: 5
Submitted By: Graham Horler (grahamh)
Assigned to: Martin v. Löwis (loewis)
Summary: Fix Tkinter Tcl-commands memory-leaks

Initial Comment:
Fix 8 memory-leaks by cleaning up created Tcl commands
automatically.

I attach a patch against Tkinter 47021.

=== Long explanation ===

I was bitten by a memory leak in Tkinter - 25MB per day
on a long-running process.  A net search found a couple
unrelated Tkinter leaks, and gave me some clues. 
Investigation using the tracing feature in tkleak.py
(see link) found the bug.

I searched for more similar leaks, and fixed them too.

The reasoning for patch #1121234 gives the reason for
the changes to _register() and deletecommand().

See http://www.uk.debian.org/~graham/python/tkleak.py
for my leak tracing and test script.


----------------------------------------------------------------------

>Comment By: Graham Horler (grahamh)
Date: 2006-07-24 10:29

Message:
Logged In: YES 
user_id=543663

> The patch looks wrong. Why are you deleting the
> _tkcommands of the master widget if the variable
> is deleted? The master could live much longer,
> and the commands might still be needed.

AIUI, Tkinter callbacks (Button and Scrollbar commands, Text
[xy]view, event, protocol and variable bindings, after
callbacks etc) should always be given a Python callable, and
not the Tcl name of an already bound Python command.
Example:
 b1 = Button(root, command=pressed)
 b2 = Button(root, command=b1['command']) # Share command
 b1.destroy()
 b2.invoke() # Callback is invalid, and rightly so
Given that, when a Variable is deleted, is needs to clean up
the Tcl commands it created, as no other widget has a
reference to them, and they are no longer needed, and there
will be no other way of deleting them.
By the time __del__() deletes any 'u' callbacks, they have
already been called, as globalunsetvar is called first, so
this is safe.

> What is the purpose of the changes to trace_variable?
> You are supposed to invoke trace_vdelete to release the
> callback.

Is it the aim for Tkinter to work in a similar way to
Python's reference counted and garbage collected mem-man?  I
assume it is, so the changes track commands associated with
the variable, for cleanup on collection.
See next comment below for explanation of TclError.

> Why are you catching TclError in so many cases? Under what
> circumstances can you even get an error?

The following all raise TclError:
w.after("spam", eggs) # bad argument "spam": must be cancel,
idle, info, or a number
w.bind("<spam>", eggs) # bad event type or keysym "spam"
w.bind_all("<spam>", eggs) # bad event type or keysym "spam"
w.bind_class("Button", "<spam>", eggs) # bad event type or
keysym "spam"
w.config(spam=eggs) # unknown option "-spam"
v.trace_variable("spam", eggs) # bad operations "spam":
should be one or more of rwu

When the exception is raised, the 'eggs' Tcl command for the
'spam' callback has already been created.  The exception
means the "command-id" is never returned for use in cleaning
up manually.  So, the patch cleans up on exception
automatically.  I don't think the argument that it's OK for
incorrect use to result in memory leaks holds any water :-)
 I may of course be missing the obvious.

> I think I would prefer if this patch was split into many
> individual ones, each one fixing only a single
> bug (assuming there are multiple bugs in Tkinter).

Sorry for the rushed patch, I noticed the release schedule
for Python2.5 and just put together the patch from
monkey-patch code I had already been using, tested it and
uploaded.  The tkleak.py program mentioned tests all the
fixes, but I did not have time to add them to the Python
test suite.
I realise you probably have many demands on your time
(fielding loads of patches like this one :-), like I do
(baby imminent! work demands etc.), so I hope the
explanations above help (I should have explained all this
before), if not I may be able to submit separate patches and
tests at a later date.

Many thanks, Graham Horler

----------------------------------------------------------------------

Comment By: Martin v. Löwis (loewis)
Date: 2006-07-24 07:15

Message:
Logged In: YES 
user_id=21627

The patch looks wrong. Why are you deleting the _tkcommands
of the master widget if the variable is deleted? The master
could live much longer, and the commands might still be needed.

What is the purpose of the changes to trace_variable? You
are supposed to invoke trace_vdelete to release the callback.

Why are you catching TclError in so many cases? Under what
circumstances can you even get an error?

I think I would prefer if this patch was split into many
individual ones, each one fixing only a single bug (assuming
there are multiple bugs in Tkinter).

----------------------------------------------------------------------

Comment By: Graham Horler (grahamh)
Date: 2006-07-19 11:33

Message:
Logged In: YES 
user_id=543663

I fixed a bug in the original patch: when destroying a
window which had Variable instances attached which in turn
had trace commands bound, Tkinter.py was trying to delete
the commands twice, as the command was mentioned in Variable
instance _tclCommands and _root()._tcl_Commands.

Also fixed 4 more leaks occurring when TclError is raised
after a callback has been created.

I have added 6 tests to tkleak.py to test the additional 4
fixes.

The patch is against 50704, hope it helps.

Thanks for your hard work, and for accepting my other
Tkinter.py patch.


----------------------------------------------------------------------

Comment By: Graham Horler (grahamh)
Date: 2006-07-18 17:18

Message:
Logged In: YES 
user_id=543663

The python version I am using in production is 2.1 (for
historical reasons), however the memory leak bugs are in 2.1
through to 2.5.

I can generate a patch against any of the older versions
(e.g. 2.4) if anyone is interested.


----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1524639&group_id=5470
_______________________________________________
Patches mailing list
Patches@python.org
http://mail.python.org/mailman/listinfo/patches

Reply via email to