-
Notifications
You must be signed in to change notification settings - Fork 51
Memory Management
Go is a language with GC, while C++ is not - this makes memory management a bit complicated. For now, wxGo cannot fully automatically handle this issue, but it can be easily done with users' help.
wx-Objects can be allocated and initialized using wx.NewCLASS
, for example you can get a wxSizer
object by calling wx.NewSizer
. All wx.NewCLASS
functions will allocate memory on C++ side (on heap), thus it will not be tracked by Go's garbage collector. So you have to free the memory your self, by calling wx.DeleteCLASS
(e.g wx.DeleteSizer
).
However, a wxSizer
is usually in the GUI hierarchy, which means it will be taken own by other object. For example,
dlg := wx.NewDialog(...)
bSizer := wx.NewBoxSizer(wx.VERTICAL)
dlg.SetSizer(bSizer) // dlg will own bSizer
When dlg
is destroyed, bSizer
will automatically destroyed by dlg
. So we don't have to call wx.DeleteSizer
to free it.
In fact, everything goes well with wx.NewCLASS
and wx.DeleteCLASS
- we use wx.NewCLASS
to get an object, and use wx.DeleteCLASS
to destroy one when needed. However, it can be a little annoying in some cases:
// In C++, we can write: `dlg.SetSize(wxSize(400, 400))` with no problem.
// In Go, we have to:
size := wx.NewSize(400, 400) // wxSize* size = new wxSize(400, 400);
dlg.SetSize(size) // dlg.SetSize(*size);
wx.DeleteSize(size) // delete size;
// What is more annoying:
// In C++: wxAuiPaneInfo().Name("tb1").Caption("Big Toolbar").ToolbarPane().Top()
// In Go:
wx.NewAuiPaneInfo().Name("tb1").Caption("Big Toolbar").ToolbarPane().Top()
// Memory leaks!!
To make it easier, every object have another NewCLASST
function that can be used: the trailing T
represents for
"tracked", that means the wx-object will be tracked by Go's GC. So we can safely write the following code:
dlg.SetSize(wx.NewSize(400, 400))
paneInfo := wx.NewAuiPaneInfoT().Name("tb1").Caption("Big Toolbar").ToolbarPane().Top()
Please be careful about the ownership - the following code may crash at any time when Go's GC starts to run:
dlg := wx.NewDialog(...)
bSizer := wx.NewBoxSizerT(wx.VERTICAL) // Note the trailing T
dlg.SetSizer(bSizer) // dlg will own bSizer
If bSizer
is collected by Go's GC, the wxBoxSizer
object will also be freed. This may cause double-free error or other segmentation faults.
wx.NewCLASST
is only a simple wrapper of wx.NewCLASS
. For example:
func NewSizeT(a ...interface{}) Size {
ret := NewSize(a...)
ret.SwigTrackObject()
return ret
}
As you can see, the trick is done by SwigTrackObject
method. You can manually call it when you want Go's GC to delete the object, or call SwigUntrackObject
method to let Go's GC not track it.
-
p := wx.NewCLASS
/p.SwigUntrackObject()
, p is owned by you (which means you are responsible for freeing it) -
obj.TAKEOWN(p)
, p is owned by obj, and obj is responsible for freeing p. There are several methods that take the ownership of other objects, please refer the wxWidgets document. -
p := wx.NewCLASST
/p.SwigTrackObject()
, p is owned by Go's GC (which means it will free the object when p is unreachable)
There are some special notes on wxFrame and wxDialog:
- √ When we click the close botton of a
wxFrame
, by default theDestroy
will be called and it will be deleted by itself (and also all children). - × However when we close a
wxDialog
, theDestroy
won't be called by default and we have to manually destroy it.
Useful materials: