我使用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的定义,并且应用程序仍然泄漏。
答案 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()