以下示例将由于tk.createcommand
造成内存泄漏:
import tkinter
import gc
class Foo:
def __init__(self):
self.tk = tkinter.Tcl()
self.tk.createcommand("someCommand", self.someCommand)
def someCommand(self):
pass
if __name__ == "__main__":
while 1:
f = Foo()
# f.tk.deletecommand("someCommand")
# del f
# gc.collect()
如果删除tk.createcommand
,一切正常,del f
和gc.collect()
无效,并且tk.deletecommand
将抛出_tkinter.TclError: can't delete Tcl command
。
是否有任何方法可以删除创建的命令或清理内存?我不不使用tkinter GUI,我需要它来调用一些旧式tcl代码。
python
Python 3.7.3 (default, Mar 26 2019, 21:43:19)
[GCC 8.2.1 20181127] on linux
答案 0 :(得分:1)
尽管在完整的Tcl环境中,解释器是完全可破坏的(如果不是便宜的)对象,但Tkinter自己的参考Tcl解释器(相当重的实体)似乎并不容易删除;它与基础C _tkinter
对象的寿命相关,并且有点复杂……到这一点,我很难判断删除该对象并对其进行垃圾回收会导致事情变得可重载,或者您是否愿意只是为将来的怪异做好准备。如果您也不必加载Tk,则可能有效(因为Tk有点麻烦)。最终。
因此,最好是最好的,如果您不需要的话可以避免重新加载,并且如果您不创建Tcl()
的新实例,也最好您实际上并不需要它们。毕竟这有点像说要创建一个新的Python解释器…,所以它可能不应该在普通代码中紧密循环地完成。
您已经找到deletecommand
;命令 被设计为廉价地创建和销毁。
是否可以在子进程中运行代码?如果没有Tk,这应该相当简单,并且操作系统可以很好地清理进程。有很多方法可以做到这一点。哪一个最好取决于您正在执行的操作的细节(尤其是交互性和移动的数据量)。
答案 1 :(得分:0)
我找到了一个解决方案,尽管此解决方案在我的情况下不起作用。不知道为什么,但是我们要做的只是这个小的演示代码,所以我切换到multiprocessing
。
您必须明确呼叫deletecommand
:
import tkinter
import gc
class Foo:
def __init__(self):
self.tk = tkinter.Tcl()
self.tk.createcommand("someCommand", self.someCommand)
print("Foo intialized")
# self.tk.eval('rename someCommand ""')
def someCommand(self):
pass
def __del__(self):
print("DESTRUCTOR called!")
if __name__ == "__main__":
while 1:
f = Foo()
f.tk.tk.deletecommand("someCommand")
del f
gc.collect()
当心!将调用置于__del__
中将不起作用,因为析构函数将由于内存泄漏而永远不会被调用:
import tkinter
import gc
class Foo:
def __init__(self):
self.tk = tkinter.Tcl()
self.tk.createcommand("someCommand", self.someCommand)
print("Foo intialized")
# self.tk.eval('rename someCommand ""')
def someCommand(self):
pass
def __del__(self):
f.tk.tk.deletecommand("someCommand")
print("DESTRUCTOR called!")
if __name__ == "__main__":
while 1:
f = Foo()
# f.tk.tk.deletecommand("someCommand")
del f
gc.collect()