如何清理tk.createcommand?
How to clean up tk.createcommand?
以下示例将由于 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
虽然在完整的 Tcl 环境中解释器是完全可销毁的(如果不是廉价的)对象,Tkinter 自己的参考 Tcl 解释器(一个相当重量级的实体)似乎不是一个容易删除的对象;它与底层 C _tkinter
对象的生命周期有关,这有点复杂……以至于我很难判断删除它和垃圾收集它是否会导致事情变得可重新加载或者你是否会只是为未来的怪异做好准备。它 可能 可以工作,前提是你没有加载 Tk(因为 Tk 有点挑剔)。终于。
因此,真的如果你能避免在不需要时重新加载它是最好的,而且如果你不创建新实例也是最好的Tcl()
如果您实际上不需要它们。毕竟这有点像说制作一个新的 Python 解释器......所以它可能不应该在普通代码中的紧密循环中完成。
您已经找到了deletecommand
;命令被设计成创建和销毁成本低廉。
是否可以 运行 子进程中的代码?没有 Tk about,那应该相当简单,并且进程被 OS 清理得非常好。有很多方法可以做到这一点;哪一个最好将取决于您正在做的事情的细节(尤其是有多少交互性以及您要移动多少数据)。
我找到了一个解决方案,尽管这个解决方案不适用于我的情况。不知道为什么,但我们做的不仅仅是这个小演示代码,所以我切换到 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()
以下示例将由于 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
虽然在完整的 Tcl 环境中解释器是完全可销毁的(如果不是廉价的)对象,Tkinter 自己的参考 Tcl 解释器(一个相当重量级的实体)似乎不是一个容易删除的对象;它与底层 C _tkinter
对象的生命周期有关,这有点复杂……以至于我很难判断删除它和垃圾收集它是否会导致事情变得可重新加载或者你是否会只是为未来的怪异做好准备。它 可能 可以工作,前提是你没有加载 Tk(因为 Tk 有点挑剔)。终于。
因此,真的如果你能避免在不需要时重新加载它是最好的,而且如果你不创建新实例也是最好的Tcl()
如果您实际上不需要它们。毕竟这有点像说制作一个新的 Python 解释器......所以它可能不应该在普通代码中的紧密循环中完成。
您已经找到了deletecommand
;命令被设计成创建和销毁成本低廉。
是否可以 运行 子进程中的代码?没有 Tk about,那应该相当简单,并且进程被 OS 清理得非常好。有很多方法可以做到这一点;哪一个最好将取决于您正在做的事情的细节(尤其是有多少交互性以及您要移动多少数据)。
我找到了一个解决方案,尽管这个解决方案不适用于我的情况。不知道为什么,但我们做的不仅仅是这个小演示代码,所以我切换到 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()