Tkinter - memory leak with canvasWhich Python memory profiler is recommended?Install tkinter for Pythontkinter: using scrollbars on a canvasHow to clear Tkinter Canvas?Tkinter Canvas create_window()Tkinter Canvas Update Memory LeakMove a tkinter canvas with MouseTkinter Text and Itemconfigure Memory LeakItemconfigure() and memory leak with tkinterTkinter canvas zoom + move/pan

Pre-Employment Background Check With Consent For Future Checks

Are Captain Marvel's powers affected by Thanos breaking the Tesseract and claiming the stone?

How do I fix the group tension caused by my character stealing and possibly killing without provocation?

Why would five hundred and five be same as one?

What is this high flying aircraft over Pennsylvania?

What (the heck) is a Super Worm Equinox Moon?

Is there a RAID 0 Equivalent for RAM?

Do people actually use the word "kaputt" in conversation?

Ways of geometrical multiplication

What is the meaning of "You've never met a graph you didn't like?"

When is "ei" a diphthong?

How to test the sharpness of a knife?

Why is the Sun approximated as a black body at ~ 5800 K?

How to make money from a browser who sees 5 seconds into the future of any web page?

Would a primitive species be able to learn English from reading books alone?

Why does a 97 / 92 key piano exist by Bösendorfer?

Given this phrasing in the lease, when should I pay my rent?

Showing mass murder in a kid's book

Check if object is null and return null

Review your own paper in Mathematics

Isometric embedding of a genus g surface

Do I have to know the General Relativity theory to understand the concept of inertial frame?

Why Shazam when there is already Superman?

How to reduce predictors the right way for a logistic regression model



Tkinter - memory leak with canvas


Which Python memory profiler is recommended?Install tkinter for Pythontkinter: using scrollbars on a canvasHow to clear Tkinter Canvas?Tkinter Canvas create_window()Tkinter Canvas Update Memory LeakMove a tkinter canvas with MouseTkinter Text and Itemconfigure Memory LeakItemconfigure() and memory leak with tkinterTkinter canvas zoom + move/pan













1















I have a Python script that handles Modbus communications. One feature I added was a "graph" that shows the response times along with a color coded line that indicates if the response was successful, had an exception, or an error. The graph is just a scrollable canvas widget from Tkinter.



After graphing a certain number of lines old lines will be deleted and then a new one will be added to the end. For this example I have it set to 10, which means there will never be more than 10 lines on the canvas at once.



The code works correctly but there is a memory leak somewhere in this function. I let it run for about 24 hours and it took about 6x more memory after 24 hours. The function is part of a larger class.



My current guess is that my code causes the canvas size to constantly "expand," which slowly eats up the memory.



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)


One solution could be loop back to the start of the graph once a limit is reached but I would rather not do this since it may be confusing where the graph starts. Usually I have far more responses than 10.



EDIT:



I'm still doing to trail and error stuff but it looks like the memory leak can be eliminated with Bryan's suggestion as long as the line attributes are not changed via itemconfig. The code below should be able to run as is, if you're on python 2.7 change the import statement from tkinter to Tkinter (lower case vs uppercase t). This code will have the memory leak in it. Comment out the itemconfig line and it will be eliminated.



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)

#if i comment out the line below the memory leak goes away.
self.responseTimeCanvas.itemconfig(self.lineList[self.responseIndex % self.maxLine], fill=RGB(random.randint(0,255), random.randint(0,255), random.randint(0,255)))
else:
self.lineList.append(self.responseTimeCanvas.create_rectangle(self.xPos, self.responseWidth, self.xPos + 4, self.responseWidth-self.lineLength,
fill=RGB(random.randint(0,255), random.randint(0,255), random.randint(0,255)), outline=''))


self.xPos += 5 #will cause the next line to start 5 pixels later. MEMORY LEAK HERE?
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()









share|improve this question
























  • I don't see anything obviously wrong...but you could try changing the existing Canvas object in lineList[0] via the widget's itemconfigure() method and modifying the rectangle that already exists, instead of deleting it and creating a new one as you're now doing.

    – martineau
    Mar 7 at 22:30












  • That's my plan B right now. I think it looks better when constantly adding to the end and it makes it more clear cut what order things happened. I have an older version of this script and the leak exists but doesn't cause problems unless I'm running it for multiple days while doing rapid reads. After that it will freeze up or crash.

    – Dave1551
    Mar 7 at 22:36











  • You can change the order of the existing items in a Canvas display list by calling the widget's tag_Lower() or tag_raise() methods.

    – martineau
    Mar 7 at 22:40
















1















I have a Python script that handles Modbus communications. One feature I added was a "graph" that shows the response times along with a color coded line that indicates if the response was successful, had an exception, or an error. The graph is just a scrollable canvas widget from Tkinter.



After graphing a certain number of lines old lines will be deleted and then a new one will be added to the end. For this example I have it set to 10, which means there will never be more than 10 lines on the canvas at once.



The code works correctly but there is a memory leak somewhere in this function. I let it run for about 24 hours and it took about 6x more memory after 24 hours. The function is part of a larger class.



My current guess is that my code causes the canvas size to constantly "expand," which slowly eats up the memory.



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)


One solution could be loop back to the start of the graph once a limit is reached but I would rather not do this since it may be confusing where the graph starts. Usually I have far more responses than 10.



EDIT:



I'm still doing to trail and error stuff but it looks like the memory leak can be eliminated with Bryan's suggestion as long as the line attributes are not changed via itemconfig. The code below should be able to run as is, if you're on python 2.7 change the import statement from tkinter to Tkinter (lower case vs uppercase t). This code will have the memory leak in it. Comment out the itemconfig line and it will be eliminated.



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)

#if i comment out the line below the memory leak goes away.
self.responseTimeCanvas.itemconfig(self.lineList[self.responseIndex % self.maxLine], fill=RGB(random.randint(0,255), random.randint(0,255), random.randint(0,255)))
else:
self.lineList.append(self.responseTimeCanvas.create_rectangle(self.xPos, self.responseWidth, self.xPos + 4, self.responseWidth-self.lineLength,
fill=RGB(random.randint(0,255), random.randint(0,255), random.randint(0,255)), outline=''))


self.xPos += 5 #will cause the next line to start 5 pixels later. MEMORY LEAK HERE?
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()









share|improve this question
























  • I don't see anything obviously wrong...but you could try changing the existing Canvas object in lineList[0] via the widget's itemconfigure() method and modifying the rectangle that already exists, instead of deleting it and creating a new one as you're now doing.

    – martineau
    Mar 7 at 22:30












  • That's my plan B right now. I think it looks better when constantly adding to the end and it makes it more clear cut what order things happened. I have an older version of this script and the leak exists but doesn't cause problems unless I'm running it for multiple days while doing rapid reads. After that it will freeze up or crash.

    – Dave1551
    Mar 7 at 22:36











  • You can change the order of the existing items in a Canvas display list by calling the widget's tag_Lower() or tag_raise() methods.

    – martineau
    Mar 7 at 22:40














1












1








1








I have a Python script that handles Modbus communications. One feature I added was a "graph" that shows the response times along with a color coded line that indicates if the response was successful, had an exception, or an error. The graph is just a scrollable canvas widget from Tkinter.



After graphing a certain number of lines old lines will be deleted and then a new one will be added to the end. For this example I have it set to 10, which means there will never be more than 10 lines on the canvas at once.



The code works correctly but there is a memory leak somewhere in this function. I let it run for about 24 hours and it took about 6x more memory after 24 hours. The function is part of a larger class.



My current guess is that my code causes the canvas size to constantly "expand," which slowly eats up the memory.



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)


One solution could be loop back to the start of the graph once a limit is reached but I would rather not do this since it may be confusing where the graph starts. Usually I have far more responses than 10.



EDIT:



I'm still doing to trail and error stuff but it looks like the memory leak can be eliminated with Bryan's suggestion as long as the line attributes are not changed via itemconfig. The code below should be able to run as is, if you're on python 2.7 change the import statement from tkinter to Tkinter (lower case vs uppercase t). This code will have the memory leak in it. Comment out the itemconfig line and it will be eliminated.



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)

#if i comment out the line below the memory leak goes away.
self.responseTimeCanvas.itemconfig(self.lineList[self.responseIndex % self.maxLine], fill=RGB(random.randint(0,255), random.randint(0,255), random.randint(0,255)))
else:
self.lineList.append(self.responseTimeCanvas.create_rectangle(self.xPos, self.responseWidth, self.xPos + 4, self.responseWidth-self.lineLength,
fill=RGB(random.randint(0,255), random.randint(0,255), random.randint(0,255)), outline=''))


self.xPos += 5 #will cause the next line to start 5 pixels later. MEMORY LEAK HERE?
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()









share|improve this question
















I have a Python script that handles Modbus communications. One feature I added was a "graph" that shows the response times along with a color coded line that indicates if the response was successful, had an exception, or an error. The graph is just a scrollable canvas widget from Tkinter.



After graphing a certain number of lines old lines will be deleted and then a new one will be added to the end. For this example I have it set to 10, which means there will never be more than 10 lines on the canvas at once.



The code works correctly but there is a memory leak somewhere in this function. I let it run for about 24 hours and it took about 6x more memory after 24 hours. The function is part of a larger class.



My current guess is that my code causes the canvas size to constantly "expand," which slowly eats up the memory.



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)


One solution could be loop back to the start of the graph once a limit is reached but I would rather not do this since it may be confusing where the graph starts. Usually I have far more responses than 10.



EDIT:



I'm still doing to trail and error stuff but it looks like the memory leak can be eliminated with Bryan's suggestion as long as the line attributes are not changed via itemconfig. The code below should be able to run as is, if you're on python 2.7 change the import statement from tkinter to Tkinter (lower case vs uppercase t). This code will have the memory leak in it. Comment out the itemconfig line and it will be eliminated.



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)

#if i comment out the line below the memory leak goes away.
self.responseTimeCanvas.itemconfig(self.lineList[self.responseIndex % self.maxLine], fill=RGB(random.randint(0,255), random.randint(0,255), random.randint(0,255)))
else:
self.lineList.append(self.responseTimeCanvas.create_rectangle(self.xPos, self.responseWidth, self.xPos + 4, self.responseWidth-self.lineLength,
fill=RGB(random.randint(0,255), random.randint(0,255), random.randint(0,255)), outline=''))


self.xPos += 5 #will cause the next line to start 5 pixels later. MEMORY LEAK HERE?
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()






python tkinter tkinter-canvas






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 8 at 14:52







Dave1551

















asked Mar 7 at 22:06









Dave1551Dave1551

284




284












  • I don't see anything obviously wrong...but you could try changing the existing Canvas object in lineList[0] via the widget's itemconfigure() method and modifying the rectangle that already exists, instead of deleting it and creating a new one as you're now doing.

    – martineau
    Mar 7 at 22:30












  • That's my plan B right now. I think it looks better when constantly adding to the end and it makes it more clear cut what order things happened. I have an older version of this script and the leak exists but doesn't cause problems unless I'm running it for multiple days while doing rapid reads. After that it will freeze up or crash.

    – Dave1551
    Mar 7 at 22:36











  • You can change the order of the existing items in a Canvas display list by calling the widget's tag_Lower() or tag_raise() methods.

    – martineau
    Mar 7 at 22:40


















  • I don't see anything obviously wrong...but you could try changing the existing Canvas object in lineList[0] via the widget's itemconfigure() method and modifying the rectangle that already exists, instead of deleting it and creating a new one as you're now doing.

    – martineau
    Mar 7 at 22:30












  • That's my plan B right now. I think it looks better when constantly adding to the end and it makes it more clear cut what order things happened. I have an older version of this script and the leak exists but doesn't cause problems unless I'm running it for multiple days while doing rapid reads. After that it will freeze up or crash.

    – Dave1551
    Mar 7 at 22:36











  • You can change the order of the existing items in a Canvas display list by calling the widget's tag_Lower() or tag_raise() methods.

    – martineau
    Mar 7 at 22:40

















I don't see anything obviously wrong...but you could try changing the existing Canvas object in lineList[0] via the widget's itemconfigure() method and modifying the rectangle that already exists, instead of deleting it and creating a new one as you're now doing.

– martineau
Mar 7 at 22:30






I don't see anything obviously wrong...but you could try changing the existing Canvas object in lineList[0] via the widget's itemconfigure() method and modifying the rectangle that already exists, instead of deleting it and creating a new one as you're now doing.

– martineau
Mar 7 at 22:30














That's my plan B right now. I think it looks better when constantly adding to the end and it makes it more clear cut what order things happened. I have an older version of this script and the leak exists but doesn't cause problems unless I'm running it for multiple days while doing rapid reads. After that it will freeze up or crash.

– Dave1551
Mar 7 at 22:36





That's my plan B right now. I think it looks better when constantly adding to the end and it makes it more clear cut what order things happened. I have an older version of this script and the leak exists but doesn't cause problems unless I'm running it for multiple days while doing rapid reads. After that it will freeze up or crash.

– Dave1551
Mar 7 at 22:36













You can change the order of the existing items in a Canvas display list by calling the widget's tag_Lower() or tag_raise() methods.

– martineau
Mar 7 at 22:40






You can change the order of the existing items in a Canvas display list by calling the widget's tag_Lower() or tag_raise() methods.

– martineau
Mar 7 at 22:40













2 Answers
2






active

oldest

votes


















1














The underlying tk canvas doesn't reuse or recycle object identifiers. Whenever you create a new object, a new identifier is generated. The memory of these objects is never reclaimed.



Note: this is memory inside the embedded tcl interpreter, rather than memory managed by python.



The solution is to reconfigure old, no longer used elements rather than deleting them and creating new ones.






share|improve this answer























  • I don't know the internals like you do, but it sounds like you're confirming that my suggestion would avoid the issue.

    – martineau
    Mar 7 at 22:46






  • 1





    @martineau: I didn't see your suggestion until now, but yes, we agree on the solution.

    – Bryan Oakley
    Mar 7 at 22:57











  • Thanks. @martineau I may have misinterpreted your suggestion. I changed my code to hopefully fix this issue. Rather than deleting the line when it reaches the limit I take the first line and place it at the end. For now I don't change any other attributes. This means the canvas is still 'expanding' but it looks like there is no longer a memory leak. I'll have to let it run for a few hours before I can be sure. I'll update this thread once it runs long enough

    – Dave1551
    Mar 7 at 23:10












  • @Dave1551: FWIW, that sounds basically correct as I don't think not also having a call to itemconfigure() to change the object's attributes will matter - but again I don't know a lot about the internal details.

    – martineau
    Mar 7 at 23:19












  • The memory leak went away if i don't use the itemconfig to change the lines' color. When just moving the line the memory started at 6.8MB, then went up to 7.2 pretty quickly, then eventually dropped to 2MB which I can't explain. When changing the color with itemcofig the memory slowly increases. I added standalone code to my original post if anyone want's to experiment with this too.

    – Dave1551
    Mar 8 at 14:55


















0














Here's the code with no memory leak. The original source of the leak was me deleting the old line then creating a new one. This solution moves the first the line to the end then change's its attributes as necessary. I had a second 'leak' in my example code where I was picking a random color each time which lead to the number of colors used eating up a lot of memory. This code just prints green lines but the length will be random.



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()





share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55053568%2ftkinter-memory-leak-with-canvas%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    The underlying tk canvas doesn't reuse or recycle object identifiers. Whenever you create a new object, a new identifier is generated. The memory of these objects is never reclaimed.



    Note: this is memory inside the embedded tcl interpreter, rather than memory managed by python.



    The solution is to reconfigure old, no longer used elements rather than deleting them and creating new ones.






    share|improve this answer























    • I don't know the internals like you do, but it sounds like you're confirming that my suggestion would avoid the issue.

      – martineau
      Mar 7 at 22:46






    • 1





      @martineau: I didn't see your suggestion until now, but yes, we agree on the solution.

      – Bryan Oakley
      Mar 7 at 22:57











    • Thanks. @martineau I may have misinterpreted your suggestion. I changed my code to hopefully fix this issue. Rather than deleting the line when it reaches the limit I take the first line and place it at the end. For now I don't change any other attributes. This means the canvas is still 'expanding' but it looks like there is no longer a memory leak. I'll have to let it run for a few hours before I can be sure. I'll update this thread once it runs long enough

      – Dave1551
      Mar 7 at 23:10












    • @Dave1551: FWIW, that sounds basically correct as I don't think not also having a call to itemconfigure() to change the object's attributes will matter - but again I don't know a lot about the internal details.

      – martineau
      Mar 7 at 23:19












    • The memory leak went away if i don't use the itemconfig to change the lines' color. When just moving the line the memory started at 6.8MB, then went up to 7.2 pretty quickly, then eventually dropped to 2MB which I can't explain. When changing the color with itemcofig the memory slowly increases. I added standalone code to my original post if anyone want's to experiment with this too.

      – Dave1551
      Mar 8 at 14:55















    1














    The underlying tk canvas doesn't reuse or recycle object identifiers. Whenever you create a new object, a new identifier is generated. The memory of these objects is never reclaimed.



    Note: this is memory inside the embedded tcl interpreter, rather than memory managed by python.



    The solution is to reconfigure old, no longer used elements rather than deleting them and creating new ones.






    share|improve this answer























    • I don't know the internals like you do, but it sounds like you're confirming that my suggestion would avoid the issue.

      – martineau
      Mar 7 at 22:46






    • 1





      @martineau: I didn't see your suggestion until now, but yes, we agree on the solution.

      – Bryan Oakley
      Mar 7 at 22:57











    • Thanks. @martineau I may have misinterpreted your suggestion. I changed my code to hopefully fix this issue. Rather than deleting the line when it reaches the limit I take the first line and place it at the end. For now I don't change any other attributes. This means the canvas is still 'expanding' but it looks like there is no longer a memory leak. I'll have to let it run for a few hours before I can be sure. I'll update this thread once it runs long enough

      – Dave1551
      Mar 7 at 23:10












    • @Dave1551: FWIW, that sounds basically correct as I don't think not also having a call to itemconfigure() to change the object's attributes will matter - but again I don't know a lot about the internal details.

      – martineau
      Mar 7 at 23:19












    • The memory leak went away if i don't use the itemconfig to change the lines' color. When just moving the line the memory started at 6.8MB, then went up to 7.2 pretty quickly, then eventually dropped to 2MB which I can't explain. When changing the color with itemcofig the memory slowly increases. I added standalone code to my original post if anyone want's to experiment with this too.

      – Dave1551
      Mar 8 at 14:55













    1












    1








    1







    The underlying tk canvas doesn't reuse or recycle object identifiers. Whenever you create a new object, a new identifier is generated. The memory of these objects is never reclaimed.



    Note: this is memory inside the embedded tcl interpreter, rather than memory managed by python.



    The solution is to reconfigure old, no longer used elements rather than deleting them and creating new ones.






    share|improve this answer













    The underlying tk canvas doesn't reuse or recycle object identifiers. Whenever you create a new object, a new identifier is generated. The memory of these objects is never reclaimed.



    Note: this is memory inside the embedded tcl interpreter, rather than memory managed by python.



    The solution is to reconfigure old, no longer used elements rather than deleting them and creating new ones.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Mar 7 at 22:40









    Bryan OakleyBryan Oakley

    220k22273433




    220k22273433












    • I don't know the internals like you do, but it sounds like you're confirming that my suggestion would avoid the issue.

      – martineau
      Mar 7 at 22:46






    • 1





      @martineau: I didn't see your suggestion until now, but yes, we agree on the solution.

      – Bryan Oakley
      Mar 7 at 22:57











    • Thanks. @martineau I may have misinterpreted your suggestion. I changed my code to hopefully fix this issue. Rather than deleting the line when it reaches the limit I take the first line and place it at the end. For now I don't change any other attributes. This means the canvas is still 'expanding' but it looks like there is no longer a memory leak. I'll have to let it run for a few hours before I can be sure. I'll update this thread once it runs long enough

      – Dave1551
      Mar 7 at 23:10












    • @Dave1551: FWIW, that sounds basically correct as I don't think not also having a call to itemconfigure() to change the object's attributes will matter - but again I don't know a lot about the internal details.

      – martineau
      Mar 7 at 23:19












    • The memory leak went away if i don't use the itemconfig to change the lines' color. When just moving the line the memory started at 6.8MB, then went up to 7.2 pretty quickly, then eventually dropped to 2MB which I can't explain. When changing the color with itemcofig the memory slowly increases. I added standalone code to my original post if anyone want's to experiment with this too.

      – Dave1551
      Mar 8 at 14:55

















    • I don't know the internals like you do, but it sounds like you're confirming that my suggestion would avoid the issue.

      – martineau
      Mar 7 at 22:46






    • 1





      @martineau: I didn't see your suggestion until now, but yes, we agree on the solution.

      – Bryan Oakley
      Mar 7 at 22:57











    • Thanks. @martineau I may have misinterpreted your suggestion. I changed my code to hopefully fix this issue. Rather than deleting the line when it reaches the limit I take the first line and place it at the end. For now I don't change any other attributes. This means the canvas is still 'expanding' but it looks like there is no longer a memory leak. I'll have to let it run for a few hours before I can be sure. I'll update this thread once it runs long enough

      – Dave1551
      Mar 7 at 23:10












    • @Dave1551: FWIW, that sounds basically correct as I don't think not also having a call to itemconfigure() to change the object's attributes will matter - but again I don't know a lot about the internal details.

      – martineau
      Mar 7 at 23:19












    • The memory leak went away if i don't use the itemconfig to change the lines' color. When just moving the line the memory started at 6.8MB, then went up to 7.2 pretty quickly, then eventually dropped to 2MB which I can't explain. When changing the color with itemcofig the memory slowly increases. I added standalone code to my original post if anyone want's to experiment with this too.

      – Dave1551
      Mar 8 at 14:55
















    I don't know the internals like you do, but it sounds like you're confirming that my suggestion would avoid the issue.

    – martineau
    Mar 7 at 22:46





    I don't know the internals like you do, but it sounds like you're confirming that my suggestion would avoid the issue.

    – martineau
    Mar 7 at 22:46




    1




    1





    @martineau: I didn't see your suggestion until now, but yes, we agree on the solution.

    – Bryan Oakley
    Mar 7 at 22:57





    @martineau: I didn't see your suggestion until now, but yes, we agree on the solution.

    – Bryan Oakley
    Mar 7 at 22:57













    Thanks. @martineau I may have misinterpreted your suggestion. I changed my code to hopefully fix this issue. Rather than deleting the line when it reaches the limit I take the first line and place it at the end. For now I don't change any other attributes. This means the canvas is still 'expanding' but it looks like there is no longer a memory leak. I'll have to let it run for a few hours before I can be sure. I'll update this thread once it runs long enough

    – Dave1551
    Mar 7 at 23:10






    Thanks. @martineau I may have misinterpreted your suggestion. I changed my code to hopefully fix this issue. Rather than deleting the line when it reaches the limit I take the first line and place it at the end. For now I don't change any other attributes. This means the canvas is still 'expanding' but it looks like there is no longer a memory leak. I'll have to let it run for a few hours before I can be sure. I'll update this thread once it runs long enough

    – Dave1551
    Mar 7 at 23:10














    @Dave1551: FWIW, that sounds basically correct as I don't think not also having a call to itemconfigure() to change the object's attributes will matter - but again I don't know a lot about the internal details.

    – martineau
    Mar 7 at 23:19






    @Dave1551: FWIW, that sounds basically correct as I don't think not also having a call to itemconfigure() to change the object's attributes will matter - but again I don't know a lot about the internal details.

    – martineau
    Mar 7 at 23:19














    The memory leak went away if i don't use the itemconfig to change the lines' color. When just moving the line the memory started at 6.8MB, then went up to 7.2 pretty quickly, then eventually dropped to 2MB which I can't explain. When changing the color with itemcofig the memory slowly increases. I added standalone code to my original post if anyone want's to experiment with this too.

    – Dave1551
    Mar 8 at 14:55





    The memory leak went away if i don't use the itemconfig to change the lines' color. When just moving the line the memory started at 6.8MB, then went up to 7.2 pretty quickly, then eventually dropped to 2MB which I can't explain. When changing the color with itemcofig the memory slowly increases. I added standalone code to my original post if anyone want's to experiment with this too.

    – Dave1551
    Mar 8 at 14:55













    0














    Here's the code with no memory leak. The original source of the leak was me deleting the old line then creating a new one. This solution moves the first the line to the end then change's its attributes as necessary. I had a second 'leak' in my example code where I was picking a random color each time which lead to the number of colors used eating up a lot of memory. This code just prints green lines but the length will be random.



    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()





    share|improve this answer



























      0














      Here's the code with no memory leak. The original source of the leak was me deleting the old line then creating a new one. This solution moves the first the line to the end then change's its attributes as necessary. I had a second 'leak' in my example code where I was picking a random color each time which lead to the number of colors used eating up a lot of memory. This code just prints green lines but the length will be random.



      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()





      share|improve this answer

























        0












        0








        0







        Here's the code with no memory leak. The original source of the leak was me deleting the old line then creating a new one. This solution moves the first the line to the end then change's its attributes as necessary. I had a second 'leak' in my example code where I was picking a random color each time which lead to the number of colors used eating up a lot of memory. This code just prints green lines but the length will be random.



        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()





        share|improve this answer













        Here's the code with no memory leak. The original source of the leak was me deleting the old line then creating a new one. This solution moves the first the line to the end then change's its attributes as necessary. I had a second 'leak' in my example code where I was picking a random color each time which lead to the number of colors used eating up a lot of memory. This code just prints green lines but the length will be random.



        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()






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Mar 9 at 16:45









        Dave1551Dave1551

        284




        284



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55053568%2ftkinter-memory-leak-with-canvas%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Can't initialize raids on a new ASUS Prime B360M-A motherboard2019 Community Moderator ElectionSimilar to RAID config yet more like mirroring solution?Can't get motherboard serial numberWhy does the BIOS entry point start with a WBINVD instruction?UEFI performance Asus Maximus V Extreme

            Identity Server 4 is not redirecting to Angular app after login2019 Community Moderator ElectionIdentity Server 4 and dockerIdentityserver implicit flow unauthorized_clientIdentityServer Hybrid Flow - Access Token is null after user successful loginIdentity Server to MVC client : Page Redirect After loginLogin with Steam OpenId(oidc-client-js)Identity Server 4+.NET Core 2.0 + IdentityIdentityServer4 post-login redirect not working in Edge browserCall to IdentityServer4 generates System.NullReferenceException: Object reference not set to an instance of an objectIdentityServer4 without HTTPS not workingHow to get Authorization code from identity server without login form

            2005 Ahvaz unrest Contents Background Causes Casualties Aftermath See also References Navigation menue"At Least 10 Are Killed by Bombs in Iran""Iran"Archived"Arab-Iranians in Iran to make April 15 'Day of Fury'"State of Mind, State of Order: Reactions to Ethnic Unrest in the Islamic Republic of Iran.10.1111/j.1754-9469.2008.00028.x"Iran hangs Arab separatists"Iran Overview from ArchivedConstitution of the Islamic Republic of Iran"Tehran puzzled by forged 'riots' letter""Iran and its minorities: Down in the second class""Iran: Handling Of Ahvaz Unrest Could End With Televised Confessions""Bombings Rock Iran Ahead of Election""Five die in Iran ethnic clashes""Iran: Need for restraint as anniversary of unrest in Khuzestan approaches"Archived"Iranian Sunni protesters killed in clashes with security forces"Archived