Kivy:在我的生命游戏中记忆泄漏了#39;码

时间:2014-04-09 09:53:54

标签: python memory-leaks kivy conways-game-of-life

我是Kivy的新人。

我正在写一部经典的生活游戏,还有更多的互动。我的Python代码正在工作,除了泄漏内存!它真的很烦人,因为我只使用相同的双胞胎结构来代替下一代的结果,所以我不指望它会成长!这是我的代码:

import kivy
kivy.require('1.7.2')

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
from kivy.uix.label import Label
from kivy.clock import Clock

import random

class UnlifeGame(Widget):
    colors = {0: [0, 0, 0], 1: [1, .8, .2], 10: [.2, .8, .2]}
    testing=0
    cells=[]

    def on_touch_down(self, touch):
        x1st = int((touch.x - 14) / 12)
        y1st = int((touch.y - 14) / 12)
        for xSquad in range(x1st, x1st + 2):
            if xSquad >= len(self.cells):
                xSquad = 0
            for ySquad in range(y1st, y1st + 2):
                if ySquad >= len(self.cells[0]):
                    ySquad = 0
                self.cells[xSquad][ySquad][self.testing] = 10
                with self.canvas:
                    Color(self.colors[10][0], self.colors[10][1], self.colors[10][2])
                    Rectangle(pos=(12+xSquad*12, 12+ySquad*12), size=(10, 10))

    def update(self, dt):
        if len(self.cells) == 0:
            with self.canvas:
                # set to Amber color
                Color(1, .8, .2)
                for xx in range(0, (self.width-14)/12):
                    self.cells.append([])
                    for yy in range(0, (self.height-14)/12):
                        # Add a cell holder
                        self.cells[xx].append([int(random.randint(0,2) == 0), 0])
                        if self.cells[xx][yy][0] == 1:
                            Rectangle(pos=(12+xx*12, 12+yy*12), size=(10, 10))
            return

        nextgen = int(self.testing == 0)
        for xx in range(0, len(self.cells)):
            for yy in range(0, len(self.cells[xx])):
                neigh = bool(self.cells[xx][yy][self.testing]) * -1 # Do not count itself!
                zombies = 0
                for nx in range(xx-1, xx+2):
                    if nx >= len(self.cells):
                        nx = 0
                    for ny in range(yy-1, yy+2):
                        if ny >= len(self.cells[xx]):
                            ny = 0
                        neigh += bool(self.cells[nx][ny][self.testing]);
                        zombies += int(self.cells[nx][ny][self.testing] / 10)
                if neigh < 2 or neigh > 3:
                    # DEATH
                    self.cells[xx][yy][nextgen] = 0
                elif neigh == 2 and self.cells[xx][yy][self.testing] == 0:
                    # NO SPAWN
                    self.cells[xx][yy][nextgen] = 0
                elif zombies >= 2:
                    # UNLIFE
                    self.cells[xx][yy][nextgen] = 10
                else:
                    # LIFE
                    self.cells[xx][yy][nextgen] = 1
                if self.cells[xx][yy][nextgen] != self.cells[xx][yy][self.testing]:
                    # Something is changed 
                    with self.canvas:
                        # set to Green, Amber OR black color
                        Color(self.colors[self.cells[xx][yy][nextgen]][0], self.colors[self.cells[xx][yy][nextgen]][1], self.colors[self.cells[xx][yy][nextgen]][2])
                        Rectangle(pos=(12+xx*12, 12+yy*12), size=(10, 10))
        self.testing = int(self.testing == 0)

class UnlifeApp(App):

    def build(self):
        game = UnlifeGame()
        Clock.schedule_interval(game.update, 0.5)
        return game

if __name__ == '__main__':
    UnlifeApp().run()

我可能需要取消设置的唯一对象是我在画布上绘制的Rectangle。但我不确定它会有用,因为我认为它只会被画布绘制并处理掉。但是,如果不是,我怎样才能将过时的那些删除它们到画布中?

我做错了什么?

1 个答案:

答案 0 :(得分:3)

你的画布代码非常低效 - 每次游戏改变时,你都会在画布上添加新的Color和Rectangle指令而不删除旧的指令,这样你就可以有效地绘制越来越多的矩形其他一切。我想这就是你所谓的内存泄漏的原因。

最好只绘制一次所有矩形,但保留对图形对象的引用并更新它们而不是绘制在顶部。这非常有效,无论是在Python中(您只制作所有对象)还是在图形层中(您只需更改现有图形对象的某些参数,而无需添加新的对象进行处理)。

执行此操作的基本方法是

with self.canvas:
    self.color = Color(...)
    self.rectangle = Rectangle(...)

之后您可以self.color.rgba = [1, 0, 0, 1]获取红色(或类似于Color的所有其他属性),或类似self.rectangle.pos = (10, 10)来更新它。在您的情况下,您不希望单引用,但可以存储所有颜色的引用列表,您所要做的就是更新正确的引用。您根本不需要更改Rectangle,因为它们的颜色是唯一改变的颜色。