It has been a frustrating couple days. I have been tracking down the bug where any wxruby-swig app will crash/segfault upon exit. Yesterday, I fixed the problem where the App object was being freed twice. Today, after several hours of debugging, I discovered that the Frame object is also being deleted twice (for a different reason). I have asked Lyle Johnson for some guidance, because it is not clear to me how to solve this problem within the swig/ruby framework. If I am not able to solve it pretty quickly, I might feel compelled to work on yet another legacy wxRuby release (0.4). It wouldn''t have a ton of new features, but would probably have the handful of method requests, along with the somewhat major fix we made right after 0.3 shipped. It might even add support for a couple classes that people have requested, but I''m not sure about that. Hopefully it would also fix the memory problems, which Nick volunteered to look in to. On the other hand, if I can fix the memory issue this weekend, then I can shift back to adding classes to wxruby-swig. That activity goes pretty quickly, so I am optimistic that I could get wxruby-swig up to the level of wxRuby 0.3 within a few weeks. Kevin
I''ve been looking into the GC problems, so I thought I''d bring a few things into discussion. In pre-swig wxruby, there is a global hashtable that maps c++ objects back to ruby VALUE''s. This is really useful for most of the ruby operations, but there is a gotcha - because the hashtable is a *ruby* hashtable, I believe it''s marking all the objects inside during the GC mark phase. Since this hashtable contains *all* wxruby objects, this would imply that *no* wxruby objects are getting collected. In wxruby-swig, there are no default GC protections. This opens up all wxruby-swig objects for collection, including Controls, Windows, etc. This means a call like def initialize() TextBox.new(self, ...); Will cause issue because the TextBox was never assigned to a variable. When the GC marks, nothing will mark the TextBox. so it will be deleted by the GC. Only problem is that it is owned by the parent window, so boom! Obviously, neither of these two scenarios are acceptable. In wxruby-swig, I think there is a two step plan. 1) Modify constructors to add pointers into a wxHash/hash_map/favorite hash table, but not a ruby table, so we can map pointers back to values. 2) Add mark functions to (a) get objects out of classes, (b) map the pointers to VALUE''s, (c) mark all relevant values. I think a few macros can help implement 2 except for things like "wxWindow", which will need to be hand coded to get all children. I think 1 can be tackled with some SWIG typemaps; a post-creation step in an "out" typemap would do the trick I think. Any input would be helpful, Nick Kevin Smith wrote:> It has been a frustrating couple days. I have been tracking down the > bug where any wxruby-swig app will crash/segfault upon exit. > Yesterday, I fixed the problem where the App object was being freed > twice. > > Today, after several hours of debugging, I discovered that the Frame > object is also being deleted twice (for a different reason). I have > asked Lyle Johnson for some guidance, because it is not clear to me > how to solve this problem within the swig/ruby framework. > > If I am not able to solve it pretty quickly, I might feel compelled to > work on yet another legacy wxRuby release (0.4). It wouldn''t have a > ton of new features, but would probably have the handful of method > requests, along with the somewhat major fix we made right after 0.3 > shipped. It might even add support for a couple classes that people > have requested, but I''m not sure about that. Hopefully it would also > fix the memory problems, which Nick volunteered to look in to. > > On the other hand, if I can fix the memory issue this weekend, then I > can shift back to adding classes to wxruby-swig. That activity goes > pretty quickly, so I am optimistic that I could get wxruby-swig up to > the level of wxRuby 0.3 within a few weeks. > > Kevin > _______________________________________________ > wxruby-users mailing list > wxruby-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/wxruby-users > >
Sudden insight! Make sure in your .i files not to have a destructor for anybody who inherits from wxWindow. Windows do their own cleanup on Destroy (frames mark themselves as destructable, windows delete their children and then delete themselves). Adding a destructor will only cause SWIG to want to destroy the window on a GC mark/sweep. This should take care of a LOT of destruction problems. Nick Kevin Smith wrote:> It has been a frustrating couple days. I have been tracking down the > bug where any wxruby-swig app will crash/segfault upon exit. > Yesterday, I fixed the problem where the App object was being freed > twice. > > Today, after several hours of debugging, I discovered that the Frame > object is also being deleted twice (for a different reason). I have > asked Lyle Johnson for some guidance, because it is not clear to me > how to solve this problem within the swig/ruby framework. > > If I am not able to solve it pretty quickly, I might feel compelled to > work on yet another legacy wxRuby release (0.4). It wouldn''t have a > ton of new features, but would probably have the handful of method > requests, along with the somewhat major fix we made right after 0.3 > shipped. It might even add support for a couple classes that people > have requested, but I''m not sure about that. Hopefully it would also > fix the memory problems, which Nick volunteered to look in to. > > On the other hand, if I can fix the memory issue this weekend, then I > can shift back to adding classes to wxruby-swig. That activity goes > pretty quickly, so I am optimistic that I could get wxruby-swig up to > the level of wxRuby 0.3 within a few weeks. > > Kevin > _______________________________________________ > wxruby-users mailing list > wxruby-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/wxruby-users > >
Nick wrote:> > I''ve been looking into the GC problems, so I thought I''d bring a few > things into discussion.Excellent.> In pre-swig wxruby, there is a global hashtable that maps c++ objects > back to ruby VALUE''s. This is really useful for most of the ruby > operations, but there is a gotcha - because the hashtable is a *ruby* > hashtable, I believe it''s marking all the objects inside during the GC > mark phase. Since this hashtable contains *all* wxruby objects, this > would imply that *no* wxruby objects are getting collected.I believe this is true. At times, I have referred to this as the memory leaks. I don''t always remember how severe the leakage is, though.> In wxruby-swig, there are no default GC protections. This opens up all > wxruby-swig objects for collection, including Controls, Windows, etc.True. For some reason, it hasn''t actually been a problem yet with the small samples (even doing GC.start all over the place). But I agree it needs to be fixed.> In wxruby-swig, I think there is a two step plan. > > 1) Modify constructors to add pointers into a wxHash/hash_map/favorite > hash table, but not a ruby table, so we can map pointers back to values.Good point. I am in the process of adding a hash map now, and will be sure to use a non-ruby hash.> 2) Add mark functions to (a) get objects out of classes, (b) map the > pointers to VALUE''s, (c) mark all relevant values.Yes. Fortunately, swig/ruby has pretty good support for this.> I think a few macros can help implement 2 except for things like > "wxWindow", which will need to be hand coded to get all children. I > think 1 can be tackled with some SWIG typemaps; a post-creation step in > an "out" typemap would do the trick I think.My plan is to handle #1 by hooking into the constructors and destructors. Every time a ruby object is created, add it to the hash. Every time is is destroyed (whether from C++ or from Ruby), remove it from the hash. For #2, there are a number of special cases with Frame, Dialog, and Window. Menus, for example, as well as all event handler callbacks. Hopefully the large majority of the other classes will not have these issues. Lyle gave me some good advice this weekend. He also shared that memory management with swig and ruby is challenging, and that I it may take a while to work through all the little issues. Kevin
Nick wrote:> > Sudden insight! > > Make sure in your .i files not to have a destructor for anybody who > inherits from wxWindow. Windows do their own cleanup on Destroy (frames > mark themselves as destructable, windows delete their children and then > delete themselves). Adding a destructor will only cause SWIG to want to > destroy the window on a GC mark/sweep. This should take care of a LOT of > destruction problems.This might (or might not) solve some problems in the short run, but I don''t think it''s the right approach in the long run. Assuming my plan of updating the pointer/object map in the constructor and destructor works, I don''t think this will be necessary. But please keep the ideas coming. This is challenging stuff that requires creative thinking. Kevin
> Lyle gave me some good advice this weekend. He also shared that memory > management with swig and ruby is challenging, and that I it may take a > while to work through all the little issues.I''m using SWIG/C# with a legacy C++ engine, and the issues are similar.> This might (or might not) solve some problems in the short run, but I > don''t think it''s the right approach in the long run. Assuming my plan > of updating the pointer/object map in the constructor and destructor > works, I don''t think this will be necessary.I disagree. Window objects are going to clean themselves up if we like it or not - that''s code in the wxwidgets framework. The big problem is what happens if a window cleans itself up and we don''t detect it? This happens *all* the time - Windows delete drop targets and sizers, documents delete themselves when there are no longer any views regestered, etc. It''s possible then the GC will try to collect an already collected object, and things go boom again. This is what happens with the client_data bug with list boxes, because list-boxes delete the client_data without their knowledge. The converse - a widget not cleaning itself up because it''s not attached to a parent, is much much less likely to happen. I''m not sure you can even create a button without a parent. I''m not saying we don''t worry about marking altogether - far from it. Any non-widget will need to be marked, or else suffer the wrath of the GC. I just think perhaps we let wx take care of widget cleanup for us for now. If we''re able to perform auto-conversion from standard ruby objects to wx utility objects (String => wxString, Time => wxDateTime), this will also help a lot too. Nick Kevin Smith wrote:> Nick wrote: > >> >> Sudden insight! >> >> Make sure in your .i files not to have a destructor for anybody who >> inherits from wxWindow. Windows do their own cleanup on Destroy >> (frames mark themselves as destructable, windows delete their >> children and then delete themselves). Adding a destructor will only >> cause SWIG to want to destroy the window on a GC mark/sweep. This >> should take care of a LOT of destruction problems. > > > This might (or might not) solve some problems in the short run, but I > don''t think it''s the right approach in the long run. Assuming my plan > of updating the pointer/object map in the constructor and destructor > works, I don''t think this will be necessary. > > But please keep the ideas coming. This is challenging stuff that > requires creative thinking. > > Kevin > _______________________________________________ > wxruby-users mailing list > wxruby-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/wxruby-users > >
Nick wrote: > Kevin wrote:>> This might (or might not) solve some problems in the short run, but I >> don''t think it''s the right approach in the long run. Assuming my plan >> of updating the pointer/object map in the constructor and destructor >> works, I don''t think this will be necessary. > > > > I disagree.Actually, I think we agree on the ideas. we might be misunderstanding each other about the mechanisms.> Window objects are going to clean themselves up if we like > it or not - that''s code in the wxwidgets framework.Yes.> The big problem is > what happens if a window cleans itself up and we don''t detect it?Yes. That''s why I plan to put a hook in *every* destructor. Any time any wrapped C++ object is deleted by anyone for any reason, the destructor will be called, and we can remove that object from the map of alive objects.> The converse - a widget not > cleaning itself up because it''s not attached to a parent, is much much > less likely to happen. I''m not sure you can even create a button without > a parent.Agreed. That is a much less severe problem. We can work on it later.> I''m not saying we don''t worry about marking altogether - far from it. > Any non-widget will need to be marked, or else suffer the wrath of the > GC.Yes.> I just think perhaps we let wx take care of widget cleanup for us > for now.I agree, but you had suggested not declaring destructors in the swig files. So far, my experiments lead me to believe that doing so will not prevent swig from deleting the C++ objects when the ruby object is freed. wxruby/swig does have a %freefunc command that we could use to disable the standard free function that is causing us trouble. But if every destructor ''detaches'' the c++ object from the ruby object (by removing it from the map and setting DATA_PTR to 0, then we won''t need to fiddle with the standard free function, because it will be harmless. The only missing piece for me right now is that swig won''t actually create a "director" class unless the real class has at least one virtual method declared. My scheme requires every class to have a director. I''m not sure if there is a simple way around this or not.> If we''re able to perform auto-conversion from standard ruby > objects to wx utility objects (String => wxString, Time => wxDateTime), > this will also help a lot too.True. It will be interesting to see how many other classes there are like those two. Kevin