Tkinter内存泄漏与画布

2024-09-29 23:17:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个处理Modbus通信的Python脚本。我添加的一个特性是一个“图形”,它显示响应时间以及一条彩色编码线,指示响应是成功的、有异常的还是错误的。这个图形只是Tkinter的一个可滚动的画布小部件。在

在绘制一定数量的线后,旧的线将被删除,然后在末尾添加一个新的。对于本例,我将其设置为10,这意味着画布上一次的行数永远不会超过10行。在

代码正常工作,但此函数中存在内存泄漏。我让它运行了大约24小时,24小时后占用了大约6倍的内存。函数是一个较大类的一部分。在

我目前的猜测是,我的代码导致画布大小不断“膨胀”,这会慢慢消耗内存。在

self.lineList = []
self.xPos = 0

def UpdateResponseTimeGraph(self):
    if not self.graphQueue.empty():
        temp = self.graphQueue.get() #pull from queue. A separate thread handles calculating the length and color of the line. 
        self.graphQueue.task_done()

        lineName     = temp[0] #assign queue values to variables
        lineLength   = temp[1]
        lineColor    = temp[2]

        if len(self.lineList) >= 10: #if more than 10 lines are on the graph, delete the first one.
            self.responseTimeCanvas.delete(self.lineList[0])
            del self.lineList[0]

        #Add line to canvas and a list so it can be referenced.
        self.lineList.append(self.responseTimeCanvas.create_rectangle(self.xPos, self.responseWidth, self.xPos + 4, self.responseWidth-lineLength, 
                                                fill=lineColor, outline=''))

        self.xPos += 5 #will cause the next line to start 5 pixels later. MEMORY LEAK HERE?

        self.responseTimeCanvas.config(scrollregion=self.responseTimeCanvas.bbox(ALL))

        self.responseTimeCanvas.xview_moveto(1.0) #move to the end of the canvas which is scrollable.



    self.graphFrame.after(10, self.UpdateResponseTimeGraph)

一种解决方案是,一旦达到极限,就可以循环回图的开头,但我不想这样做,因为这可能会混淆图形的起始位置。通常我收到的回复远远多于10条。在

编辑:

我仍在做跟踪和错误的工作,但看起来只要行属性不通过itemconfig更改,那么内存泄漏就可以通过Bryan的建议消除。下面的代码应该可以按原样运行,如果您使用的是python2.7,请将import语句从tkinter更改为tkinter(小写与大写t)。这个代码会有内存泄漏。注释掉itemconfig行,它将被删除。在

^{pr2}$

Tags: theto内存代码self图形if画布
2条回答

这是没有内存泄漏的代码。泄漏的最初来源是我删除了旧的行,然后创建了一个新的。此解决方案首先将行移到末尾,然后根据需要更改其属性。在我的示例代码中,我有第二个“泄漏”,每次我都随机选择一个颜色,这导致使用的颜色数量会占用大量内存。此代码只打印绿线,但长度是随机的。在

import tkinter
from tkinter import Tk, Frame, Canvas, ALL
import random

def RGB(r, g, b):
    return '#{:02x}{:02x}{:02x}'.format(r, g, b)

class MainUI:
    def __init__(self, master):
        self.master = master
        self.lineList = []
        self.xPos = 0

        self.maxLine = 122

        self.responseIndex = 0 


        self.responseWidth = 100
        self.responseTimeCanvas = Canvas(self.master, height=self.responseWidth)
        self.responseTimeCanvas.pack()

        self.UpdateResponseTimeGraph()

    def UpdateResponseTimeGraph(self):
        self.lineLength   = random.randint(10,99)

        if len(self.lineList) >= self.maxLine:
            self.lineLength = random.randint(5,95)
            self.responseTimeCanvas.coords(self.lineList[self.responseIndex % self.maxLine], self.xPos, self.responseWidth, self.xPos + 4, self.responseWidth-self.lineLength)

            self.responseTimeCanvas.itemconfig(self.lineList[self.responseIndex % self.maxLine], fill=RGB(100, 255, 100))
        else:
            self.lineList.append(self.responseTimeCanvas.create_rectangle(self.xPos, self.responseWidth, self.xPos + 4, self.responseWidth-self.lineLength, 
                                                fill=RGB(100, 255, 100), outline=''))


        self.xPos += 5 #will cause the next line to start 5 pixels later. 
        self.responseIndex += 1

        self.responseTimeCanvas.config(scrollregion=self.responseTimeCanvas.bbox(ALL))

        self.responseTimeCanvas.xview_moveto(1.0) #move to the end of the canvas which is scrollable.



        self.responseTimeCanvas.after(10, self.UpdateResponseTimeGraph)


mw = Tk()
mainUI = MainUI(mw)
mw.mainloop()

底层tk画布不会重用或回收对象标识符。无论何时创建新对象,都会生成一个新的标识符。这些物体的记忆永远不会被回收。在

注意:这是嵌入式tcl解释器中的内存,而不是python管理的内存。在

解决方案是重新配置旧的、不再使用的元素,而不是删除它们并创建新的元素。在

相关问题 更多 >

    热门问题