В настоящее время я пишу простую настольную игру на Python, и я просто понял, что сборка мусора не очищает отброшенные данные растрового изображения из памяти при перезагрузке изображений. Это происходит только при запуске или загрузке игры или изменении разрешения, но она умножает потребляемую память, поэтому я не могу позволить этой проблеме решить проблему.Утечка памяти при отбрасывании изображения в 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 МБ, он обрушивается, но начинает снова потреблять память.
Пожалуйста, дайте мне несколько советов, как решить эту проблему. Я благодарен за любую помощь. Спасибо. заранее.
Во-первых, это действительно проблема потребления 500 МБ? Если это так, то 500 МБ просто виртуальная память или физическая/резидентная память? Python обычно не возвращает память ОС; он держит его для повторного использования, когда вам это нужно позже. И это обычно делает вещи более быстрыми - распределение, освобождение и перераспределение десятков МБ снова и снова занимает много времени. Кроме того, на какой платформе вы работаете? Например, в 64-битной ОС X большинство процессов заканчиваются сотнями МБ виртуальной машины, а на 32-битном Linux - гораздо реже. – abarnert
Я не знаю, был ли это физический или VRAM. Я новичок в программировании, и я не знаю, как это проверить. Не могли бы вы порекомендовать кого-нибудь? Я использовал список задач из командной строки и taskmanager для отслеживания потребления памяти. Моя ОС - Win7 x64. Итак, вы говорите, что это не проблема, если она иногда рушится? Это было бы довольно облегчением. – bardosd
TaskManager показывает отдельные номера для физической и виртуальной памяти, но я не могу точно помнить, что они называются. В любом случае, если вы считаете, что может возникнуть настоящая проблема, вам нужно узнать, как работает управление памятью в Windows, прежде чем вы сможете даже исследовать. Если у вас нет реальной проблемы, и вы просто волнуетесь и не знаете, почему, просто перестаньте беспокоиться. – abarnert