wxpython应用程序中的大量内存泄漏

时间:2012-05-16 00:29:12

标签: python memory-leaks wxwidgets

我使用ode进行物理建模,使用openGL进行渲染,使用wx进行UI构建相当复杂的wxPython应用程序。一切都在游泳,直到应用程序开始崩溃。经过几天没有进展,我终于发现我的应用程序泄漏了内存。我能够以一种非常特别的速度提炼出一个小的示例脚本:

#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------

import wx
import wx.propgrid as wxpg
import random

class CoordProperty(wxpg.PyProperty):
    def __init__(self, label, name, value=(0,0,0)):
        wxpg.PyProperty.__init__(self, label, name)
        self.SetValue(value)

    def GetClassName(self):
        return "CoordProperty"

    def GetEditor(self):
        return "TextCtrl"

    def ValueToString(self, value, flags):
        x,y,z = value
        return "%f,%f,%f"%(x,y,z)


app = wx.App(False)
frame = wx.Frame(None, -1, "Test")
pg = wxpg.PropertyGridManager(frame)
props = {}

for i in range(1000):
    prop_name = "prop_%d"%i
    prop = CoordProperty("Coord", prop_name)
    pg.Append(prop)
    props[prop_name] = prop

def OnTimer(event):
    global props
    for key in props:
        props[key].SetValue((random.random(), random.random(), random.random()))

timer = wx.Timer(frame, 1)
frame.Bind(wx.EVT_TIMER, OnTimer)
timer.Start(10) # 100Hz

frame.Show()

app.MainLoop()
timer.Stop()

该示例创建一个框架,并将wxPropertyGrid放入其中。它派生出一个属性,显示一个3d坐标值,创建其中的一千个,然后从一个以100Hz运行的计时器,它将每个更新为一个随机值。这泄漏到接近10Mb /秒的某个地方,并最终崩溃。它通常在关机时崩溃。

我正在使用python 2.7& wx 2.9.3.1 msw(经典)在Windows 7上。

如果我用内置属性(例如wxpg.FloatProperty)替换我的派生CoordProperty,并相应地修改代码,那么泄漏就会消失。

有什么想法吗?或者我应该提交一个wx错误?我甚至可以在派生属性类中删除函数ValueToString的定义,并且应用程序仍然泄漏。

1 个答案:

答案 0 :(得分:3)

我使用以下代码来计算对象:

def output_memory():
    d = defaultdict(int) 
    for o in gc.get_objects():
        name = type(o).__name__  
        d[name] += 1

    items = d.items()
    items.sort(key=lambda x:x[1])
    for key, value in items:
        print key, value

发现你的程序每次事件都会增加1000个元组。因此,当您致电props[key].SetValue()时,gc尚未收集prev值。这可能是wxpg的一个错误,我们可以使用([x],[y],[z])来保存值来解决这个错误,这样你就可以在不调用SetValue()的情况下更新值:

for name, prop in props.iteritems():
    value = prop.GetValue()
    value[0][0] = random()
    value[1][0] = random()
    value[2][0] = random()
pg.Refresh()

以下是完整代码:

import wx
import wx.propgrid as wxpg
from random import random
import gc

from collections import defaultdict

def output_memory():
    d = defaultdict(int) 
    for o in gc.get_objects():
        name = type(o).__name__  
        d[name] += 1

    items = d.items()
    items.sort(key=lambda x:x[1])
    for key, value in items:
        print key, value

class CoordProperty(wxpg.PyProperty):
    def __init__(self, label, name):
        wxpg.PyProperty.__init__(self, label, name)
        self.SetValue(([0],[0],[0]))

    def GetClassName(self):
        return "CoordProperty"

    def GetEditor(self):
        return "TextCtrl"

    def GetValueAsString(self, flags):
        x,y,z = self.GetValue()   
        return "%f,%f,%f"%(x[0],y[0],z[0])   

app = wx.App(False)
frame = wx.Frame(None, -1, "Test")
pg = wxpg.PropertyGridManager(frame)
props = {}

for i in range(1000):
    prop_name = "prop_%d"%i
    prop = CoordProperty("Coord", prop_name)
    pg.Append(prop)
    props[prop_name] = prop

def OnTimer(event):
    for name, prop in props.iteritems():
        value = prop.GetValue()
        value[0][0] = random()
        value[1][0] = random()
        value[2][0] = random()
    pg.Refresh()
    #output_memory()

timer = wx.Timer(frame, 1)
frame.Bind(wx.EVT_TIMER, OnTimer)
timer.Start(10) 

frame.Show()

app.MainLoop()
timer.Stop()