Sorry, I forgot the code.
Hi,
Robin Dunn wrote:
>
> Stephen Hansen wrote:
> >
> > Are you *really* sure you're not storing any references to the notebook
pages
> elsewhere, that might be keeping them alive after destruction?
>
> Or maybe some other data that you create at the same time as the notebook
pages.
>
> -- Robin Dunn
Because it's driving me crazy I've extracted a small working example out of my
program that illustrates the problem I have: a wx.Frame with an AuiNotebook. Via
the menu you can add new pages to the notebook or delete the currently selected
page. A new page contains a wx.lib.sheet.CSheet with 13 columns and 100 rows.
The data is stored in a PyGridTableBase derived class and consists of a randomly
generated value and colour (CellAttr). Additionally a thread is started which
observes the memory usage and displays it (together with the change state to the
previous value) in the statusbar of the frame.
What you can see: each new page increases the memory usage by ~400kB. That's ok.
But deleting a page also increases the usage by ~150kB instead of releasing the
400kB.
Could someone please review the code and/or test it and give me the arbitrative
hint what's going wrong in my script:-).
Thanks a lot,
Tim
import wx,win32process, thread, time, random
import wx.aui
import wx.grid as Grid
import wx.lib.sheet as Sheet
class MyTable(Grid.PyGridTableBase):
def __init__(self, data, colnames):
Grid.PyGridTableBase.__init__(self)
self.data = data
self.colnames = colnames
self._rows = self.GetNumberRows()
self._cols = self.GetNumberCols()
def GetColLabelValue(self, col):
return self.colnames[col]
def GetNumberCols(self):
return len(self.data[0])
def GetNumberRows(self):
return len(self.data)
def GetRowLabelValue(self, row):
return unicode(row+1)
def GetValue(self, row, col):
return unicode(self.data[row][col]["value"])
def SetValue(self, row, col, value):
self.data[row][col]["value"] = value
def GetAttr(self, row, col, kind):
attr = Grid.GridCellAttr()
attr.SetBackgroundColour(self.data[row][col]["BG"])
attr.IncRef()
return attr
class MyGrid(Sheet.CSheet):
def __init__(self, prnt):
Sheet.CSheet.__init__(self, prnt)
columns = ["Param1","Param2","Param3","Param4","Param5","Param6","Param7","Param8","Param9","Param10","Param11","Param12","Param13"]
colours = [wx.BLUE, wx.GREEN, wx.RED, wx.WHITE, wx.CYAN]
InitData =
for row in range(100):
d =
for col in range(len(columns)):
d.append({"value":str(random.randint(0,100)),"BG":random.choice(colours)})
InitData.append(d)
self.._table = MyTable(InitData, columns)
self.SetTable(self._table, True)
class MyFrame(wx.Frame):
def __init__(self, prnt):
wx.Frame.__init__(self, prnt, wx.ID_ANY, "AuiNotebook Memory Test", size = (800,600))
self.Statusbar = wx.StatusBar(self, -1)
self.SetStatusBar(self.Statusbar)
self.CreateMenu()
self.myNB = wx.aui.AuiNotebook(self, wx.ID_ANY)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.LastMemUsage = win32process.GetProcessMemoryInfo(win32process.GetCurrentProcess())["WorkingSetSize"]
self.ThreadRunning = True
thread.start_new_thread(self.MemObserver, ())
self.pCnt = 1
def CreateMenu(self):
MyMenuBar = wx.MenuBar()
FileMenu = wx.Menu()
item = wx.MenuItem(FileMenu, -1, "New\tCtrl+N","Create a new Tab")
self.Bind(wx.EVT_MENU, self.OnMenuNew, item)
FileMenu.AppendItem(item)
item = wx.MenuItem(FileMenu, -1, "Close\tCtrl+W","Close the current Tab")
self.Bind(wx.EVT_MENU, self.OnMenuClose, item)
FileMenu.AppendItem(item)
MyMenuBar.Append(FileMenu, "&File")
self.SetMenuBar(MyMenuBar)
def OnMenuNew(self, evt):
newGrid = MyGrid(self.myNB)
self.myNB.AddPage(newGrid, "Grid"+str(self.pCnt))
self.pCnt+=1
evt.Skip()
def OnMenuClose(self, evt):
self.myNB.DeletePage(self.myNB.GetSelection())
evt.Skip()
def MemObserver(self):
cnt = 0
while self.ThreadRunning:
if cnt%1000 == 0:
info = win32process.GetProcessMemoryInfo(win32process.GetCurrentProcess())
if info["WorkingSetSize"] > self.LastMemUsage:
state = " (increasing)"
elif info["WorkingSetSize"] < self.LastMemUsage:
state = " (decreasing)"
else:
state = " (equal)"
self.Statusbar.SetStatusText("Memory usage: " + str(info["WorkingSetSize"]/1000) + " kB" + state)
self.LastMemUsage = info["WorkingSetSize"]
cnt = 0
cnt+=1
time.sleep(0.001)
def OnClose(self, evt):
self.ThreadRunning = False
time.sleep(0.1)
self.Destroy()
class BoaApp(wx.App):
def OnInit(self):
wx.InitAllImageHandlers()
self.main = MyFrame(None)
self..main.Show()
self.SetTopWindow(self.main)
return True
if __name__ == '__main__':
application = BoaApp(0)
application.MainLoop()