我目前正在用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 MB和作爲位圖數據大約3-3.5 MB。使用大圖輕鬆查看內存泄漏。
預期的結果,當你運行我的代碼:Python的過程週期吃掉存儲週期。當它消耗大約500 MB時,它崩潰了,但又開始消耗內存。
請給我一些建議如何解決這個問題。我很感激每一個幫助。謝謝。提前。
首先,消費500MB真的是個問題嗎?對於這個問題,500MB只是虛擬內存還是物理/駐留內存? Python通常不會將內存返回給操作系統;它會在您稍後需要時繼續使用。這通常會讓事情變得更快 - 重複分配,釋放和重新分配幾十MB需要很長時間。另外,你在哪個平臺上?例如,在64位OS X上,大多數進程最終都會有數百MB的VM,而在32位Linux上,這種情況不太常見。 – abarnert
我不知道它是物理還是VRAM。我對編程頗爲陌生,我不知道用什麼工具來檢查它。你能推薦一些嗎? 我使用命令行和taskmanager中的tasklist來跟蹤內存消耗。我的操作系統是Win7 x64。 所以你說,只要它有時會崩潰就不是問題?這將是一個相當緩解。 – bardosd
TaskManager顯示物理和虛擬內存的單獨號碼,但我不記得它們的名稱。無論如何,如果您認爲可能存在實際問題,則必須先了解內存管理在Windows中的工作原理,然後才能進行調查。如果你沒有任何實際的問題,你只是擔心,不知道爲什麼,只是不要擔心。 – abarnert