1

私は、物理モデリングにode、レンダリングにopenGL、UIにwxを使用して、かなり複雑な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座標値を表示するプロパティを取得し、それらを1000個作成してから、100Hzで実行されているタイマーから、それぞれをランダムな値に更新します。これは10Mb/秒近くのどこかでリークし、最終的にはクラッシュします。通常、シャットダウン時にもクラッシュします。

私はWindows7でpython2.7&wx 2.9.3.1 msw(クラシック)を使用しています。

派生したCoordPropertyをwxpg.FloatPropertyなどの組み込みプロパティに置き換え、それに応じてコードを変更すると、リークはなくなります。

何か案は?または、wxバグを送信する必要がありますか?派生プロパティクラスの関数ValueToStringの定義を削除することもできますが、それでもアプリはリークします。

4

1 に答える 1

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によって収集されていません。これは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()
于 2012-05-16T02:45:59.757 に答える