python memory leak

2019-09-08 22:26发布

I have an array of 'cell' objects created like so:

class Cell:
  def __init__(self, index, type, color):
    self.index = index
    self.type = type
    self.score = 0
    self.x = index%grid_size
    self.y = int(index/grid_size)
    self.color = colour


alpha = 0.8
b = 2.0
grid_size = 100
scale = 5

number_cells = grid_size*grid_size
num_cooperators = int(number_cells*alpha)       
cells = range(number_cells)
random.shuffle(cells)
cooperators = cells[0:num_cooperators]
defectors = cells[num_cooperators:number_cells]
cells = [Cell(i, 'C', blue) for i in cooperators]
cells += [Cell(i, 'D', red) for i in defectors]
cells.sort(compare)

I am grabbing attributes from them in a loop like so:

while 1:
    pixArr = pygame.PixelArray(windowSurfaceObj)
    for cell in cells:
        x = cell.x
        y = cell.y
        color = cell.color
        for y_offset in range(0,scale):
            for x_offset in range(0,scale):
                pixArr[x*scale + x_offset][y*scale + y_offset] = color
    del pixArr
    pygame.display.update()

I am leaking memory like crazy... what's going on?

2条回答
祖国的老花朵
2楼-- · 2019-09-08 22:31

The Cell class can be tighted-up (memorysize) by using slots. That ought to substantially reduce memory consumption:

class Cell(object):
    __slots__ = ('index', 'type', 'color')
    ...

The only large structure in your code is pixArr. You might want to monitor its size with sys.getsizeof. Another tool for tracking down leaks is to pretty print gc.garbage.

查看更多
做自己的国王
3楼-- · 2019-09-08 22:36

There appears to be a bug in PixelArray.

The following code replicates the memory leak by setting a single pixel each loop, and you don't even have to update the display to cause the problem:

import pygame, sys
from pygame.locals import *
ScreenWidth, ScreenHeight = 640, 480
pygame.init()
Display = pygame.display.set_mode((ScreenWidth,ScreenHeight), 0, 32)
pygame.display.set_caption('Memory Leak Test')
while True:
    PixelArray = pygame.PixelArray(Display)
    PixelArray[ScreenWidth-1][ScreenHeight-1] = (255,255,255)
    del PixelArray
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
#pygame.display.update()

If you can handle the performance hit, replacing direct pixel setting with (very short) lines avoids the memory leak, ie: pygame.draw.line(Display, Colour, (X,Y), (X,Y), 1)

查看更多
登录 后发表回答