刷新的 Tkinter 网格可能发生内存泄漏
Possible Memory Leak with Tkinter Grid that Refreshes
我创建了一个内存泄漏问题的 tkinter 程序,最初导致它在大约 40 分钟后锁定。我尝试了一个初始修复,它大大提高了性能,但一段时间后它仍然变慢,所以我认为可能存在第二次内存泄漏 and/or 我想与社区核实的其他问题。
关于程序:后端脚本每六十秒更新一次数据table,然后将其推送到制作数据的 tkinter 脚本table 在一个不错的布局。 (我在下面做了一些示例代码,它不是实际的脚本,它更长)每次刷新时,数据 table 可以有不同数量的 rows/columns。因此,我的 tkinter 脚本需要动态创建 table 并将按钮功能绑定到每个单元格。我刚刚进入 GUI 程序并选择 Tkinter 作为第一个要测试的库。我想使用 GUI 库而不是图表库,因为: 1) 我想学习如何构建基本的 GUI,并认为这将是一个有趣的应用程序; 2) 我希望能够单击我的数据的任何部分 table 并有一个 window 弹出窗口,它将在下次刷新时调整后端脚本的输入。
解决内存泄漏问题和潜在的额外内存泄漏的代码的演变:所以最初,我假设当你在网格位置。版本 1.0 以下:
import pandas as pd
import numpy as np
from tkinter import *
root = Tk()
root.configure(background='black')
#Placeholder for example code
def popupwindow():
pass
def build():
mydf = pd.DataFrame([np.arange(1, np.random.randint(3, 7)) * np.random.randint(1,10) for x in np.arange(1, np.random.randint(3, 7))])
rowindex = 1
for row in mydf.iterrows():
colindex = 1
for i in row[1]:
label = Label(root, text=str(i), width=7)
label.bind('<Button-1>', popupwindow)
label.grid(row=rowindex,column=colindex)
colindex += 1
rowindex += 1
#If grid is smaller than previous grid, remove old widgets
for label in root.grid_slaves():
if int(label.grid_info()['row']) > rowindex-1 or int(label.grid_info()['column']) > colindex-1:
label.grid_forget()
def refresh():
build()
#For purpose of example code, I made refresh rate faster than my actual program's 60 seconds
root.after(5000, refresh)
refresh()
root.mainloop()
我发现情况并非如此,这是导致第一个内存泄漏问题的原因。所以我创建了 2.0 版,它在重新创建网格之前“忘记”了所有网格从属(请参阅 build() 中的两行新代码)。这大大提高了性能,但我仍然看到 Tkinter 响应超时部分放缓。虽然,它带来了第二个问题,即在 30-40 分钟后,屏幕将部分或完全变黑(我的框架背景是黑色的)并在以下时间后停止刷新:
def build():
mydf = pd.DataFrame([np.arange(1, np.random.randint(3, 7)) * np.random.randint(1,10) for x in np.arange(1, np.random.randint(3, 7))])
# I ADDED THESE TWO LINES OF CODE
for label in root.grid_slaves():
label.grid_forget()
rowindex = 1
for row in mydf.iterrows():
colindex = 1
for i in row[1]:
label = Label(root, text=str(i), width=7)
label.bind('<Button-1>', popupwindow)
label.grid(row=rowindex,column=colindex)
colindex += 1
rowindex += 1
# REMOVED THESE 3 LINES OF CODE AS NOW REDUNDANT WITH ADDED CODE ABOVE
# for label in root.grid_slaves():
# if int(label.grid_info()['row']) > rowindex-1 or int(label.grid_info()['column']) > colindex-1:
# label.grid_forget()
仔细阅读论坛后,我在 Overstack () 上看到了这个 post,这可能表明小部件标签可能永远不会被垃圾收集,即使被遗忘。不确定这是否是一个准确的解释,但如果是的话,这可能是我的 V2.0 加班减慢的另一个可能原因,因为我总是忘记并且从不重写我的标签。因此,我为 V3 提出的解决方案是使用 if else 函数来查看标签是否已存在于给定位置,如果不创建新标签,如果存在则调整它。我的问题是,这是您的处理方式吗?您可以从我的基本示例中看到另一个内存 leak/performance 问题吗?如果您对我的代码有其他建议的调整,例如我如何动态创建数据 table,请随时提供任何 input/improvements!由于我是编程新手,所以我对不同的想法和更有效的方法持开放态度。
提前感谢您的帮助!
错误不在网格中,而是在您的代码中。每五秒钟,您就会创建一个新数据框,并为该数据框中的每一行创建新标签,并且您永远不会删除它们。相反,您只是将它们堆叠在一起。
调用 grid_forget
或 grid_remove
只会将它们从视图中删除,不会删除对象。
您需要在每次调用 refresh
时删除所有旧小部件,或者重新使用现有标签而不是创建新标签。
Therefore, my proposed solution for V3 would be to use an if else function to see if a label already exists at a given position, if it doesn’t create a new label, if it does exist then adjust it. My question is, is this how you would approach it?
是的。那,并销毁不再使用的旧小部件,而不是将它们从网格中删除。
我创建了一个内存泄漏问题的 tkinter 程序,最初导致它在大约 40 分钟后锁定。我尝试了一个初始修复,它大大提高了性能,但一段时间后它仍然变慢,所以我认为可能存在第二次内存泄漏 and/or 我想与社区核实的其他问题。
关于程序:后端脚本每六十秒更新一次数据table,然后将其推送到制作数据的 tkinter 脚本table 在一个不错的布局。 (我在下面做了一些示例代码,它不是实际的脚本,它更长)每次刷新时,数据 table 可以有不同数量的 rows/columns。因此,我的 tkinter 脚本需要动态创建 table 并将按钮功能绑定到每个单元格。我刚刚进入 GUI 程序并选择 Tkinter 作为第一个要测试的库。我想使用 GUI 库而不是图表库,因为: 1) 我想学习如何构建基本的 GUI,并认为这将是一个有趣的应用程序; 2) 我希望能够单击我的数据的任何部分 table 并有一个 window 弹出窗口,它将在下次刷新时调整后端脚本的输入。
解决内存泄漏问题和潜在的额外内存泄漏的代码的演变:所以最初,我假设当你在网格位置。版本 1.0 以下:
import pandas as pd
import numpy as np
from tkinter import *
root = Tk()
root.configure(background='black')
#Placeholder for example code
def popupwindow():
pass
def build():
mydf = pd.DataFrame([np.arange(1, np.random.randint(3, 7)) * np.random.randint(1,10) for x in np.arange(1, np.random.randint(3, 7))])
rowindex = 1
for row in mydf.iterrows():
colindex = 1
for i in row[1]:
label = Label(root, text=str(i), width=7)
label.bind('<Button-1>', popupwindow)
label.grid(row=rowindex,column=colindex)
colindex += 1
rowindex += 1
#If grid is smaller than previous grid, remove old widgets
for label in root.grid_slaves():
if int(label.grid_info()['row']) > rowindex-1 or int(label.grid_info()['column']) > colindex-1:
label.grid_forget()
def refresh():
build()
#For purpose of example code, I made refresh rate faster than my actual program's 60 seconds
root.after(5000, refresh)
refresh()
root.mainloop()
我发现情况并非如此,这是导致第一个内存泄漏问题的原因。所以我创建了 2.0 版,它在重新创建网格之前“忘记”了所有网格从属(请参阅 build() 中的两行新代码)。这大大提高了性能,但我仍然看到 Tkinter 响应超时部分放缓。虽然,它带来了第二个问题,即在 30-40 分钟后,屏幕将部分或完全变黑(我的框架背景是黑色的)并在以下时间后停止刷新:
def build():
mydf = pd.DataFrame([np.arange(1, np.random.randint(3, 7)) * np.random.randint(1,10) for x in np.arange(1, np.random.randint(3, 7))])
# I ADDED THESE TWO LINES OF CODE
for label in root.grid_slaves():
label.grid_forget()
rowindex = 1
for row in mydf.iterrows():
colindex = 1
for i in row[1]:
label = Label(root, text=str(i), width=7)
label.bind('<Button-1>', popupwindow)
label.grid(row=rowindex,column=colindex)
colindex += 1
rowindex += 1
# REMOVED THESE 3 LINES OF CODE AS NOW REDUNDANT WITH ADDED CODE ABOVE
# for label in root.grid_slaves():
# if int(label.grid_info()['row']) > rowindex-1 or int(label.grid_info()['column']) > colindex-1:
# label.grid_forget()
仔细阅读论坛后,我在 Overstack (
提前感谢您的帮助!
错误不在网格中,而是在您的代码中。每五秒钟,您就会创建一个新数据框,并为该数据框中的每一行创建新标签,并且您永远不会删除它们。相反,您只是将它们堆叠在一起。
调用 grid_forget
或 grid_remove
只会将它们从视图中删除,不会删除对象。
您需要在每次调用 refresh
时删除所有旧小部件,或者重新使用现有标签而不是创建新标签。
Therefore, my proposed solution for V3 would be to use an if else function to see if a label already exists at a given position, if it doesn’t create a new label, if it does exist then adjust it. My question is, is this how you would approach it?
是的。那,并销毁不再使用的旧小部件,而不是将它们从网格中删除。