В настоящее время я пишу простую настольную игру на Python, и я только что понял, что сборка мусора не очищает отброшенные растровые данные из памяти при перезагрузке изображений. Это происходит только тогда, когда игра запускается или загружается, или меняется разрешение, но это увеличивает потребляемую память, поэтому я не могу оставить эту проблему нерешенной.
Когда изображения перезагружаются, все ссылки переносятся на новые данные изображения, поскольку они привязаны к той же переменной, к которой были привязаны исходные данные изображения. Я попытался форсировать сборку мусора с помощью collect()
, но это не помогло.
Я написал небольшой пример, чтобы продемонстрировать мою проблему.
from tkinter import Button, DISABLED, Frame, Label, NORMAL, Tk
from PIL.Image import open
from PIL.ImageTk import PhotoImage
class App(Tk):
def __init__(self):
Tk.__init__(self)
self.text = Label(self, text = "Please check the memory usage. Then push button #1.")
self.text.pack()
self.btn = Button(text = "#1", command = lambda : self.buttonPushed(1))
self.btn.pack()
def buttonPushed(self, n):
"Cycle to open the Tab module n times."
self.btn.configure(state = DISABLED) # disable to prevent paralell cycles
if n == 100:
self.text.configure(text = "Overwriting the bitmap with itself 100 times...\n\nCheck the memory usage!\n\nUI may seem to hang but it will finish soon.")
self.update_idletasks()
for i in range(n): # creates the Tab frame whith the img, destroys it, then recreates them to overwrite the previous Frame and prevous img
b = Tab(self)
b.destroy()
if n == 100:
print(i+1,"percent of processing finished.")
if n == 1:
self.text.configure(text = "Please check the memory usage now.\nMost of the difference is caused by the bitmap opened.\nNow push button #100.")
self.btn.configure(text = "#100", command = lambda : self.buttonPushed(100))
self.btn.configure(state = NORMAL) # starting cycles is enabled again
class Tab(Frame):
"""Creates a frame with a picture in it."""
def __init__(self, master):
Frame.__init__(self, master = master)
self.a = PhotoImage(open("map.png")) # img opened, change this to a valid one to test it
self.b = Label(self, image = self.a)
self.b.pack() # Label with img appears in Frame
self.pack() # Frame appears
if __name__ == '__main__':
a = App()
Для запуска приведенного выше кода вам понадобится файл изображения PNG. Размер моего файла map.png составляет 1062×1062. В формате PNG это 1,51 МБ, а в виде растровых данных - около 3-3,5 МБ. Используйте большое изображение, чтобы легко увидеть утечку памяти.
Ожидаемый результат при запуске моего кода: процесс Python поглощает память цикл за циклом. Когда он потребляет около 500 МБ, он рушится, но снова начинает потреблять память.
Пожалуйста, дайте мне несколько советов, как решить эту проблему. Я благодарен за каждую помощь. Спасибо. заблаговременно.