Environment: Windows XP Pro + SP3 ruby (1.8.6) wxruby (1.9.9) Please see attached code (smallest code to reproduce). I''d like to know if others can reproduce this problem. I completely removed and then re-installed ruby and wxruby and was able to reproduce. I''m subclassing menus to add an extra tag. However, after some repeated menu use, the menu item becomes corrupted. The more menu items there are, the more quickly the menu item becomes corrupted. It appears (speculation) that a garbage collector or some memory reclamation code is at work that reallocates the MyMenuItem and transforms it into a MenuItem. Anybody able to reproduce? Attachments: http://www.ruby-forum.com/attachment/3119/test.rb -- Posted via http://www.ruby-forum.com/.
Hi Ridge Mcghee wrote:> I''m subclassing menus to add an extra tag. > However, after some repeated menu use, the menu > item becomes corrupted. The more menu items > there are, the more quickly the menu item becomes > corrupted. > > It appears (speculation) that a garbage collector > or some memory reclamation code is at work that > reallocates the MyMenuItem and transforms it into > a MenuItem.Hopefully I can explain. You''re right that it''s to do with garbage collection. When Ruby''s GC runs, there''s no reference anywhere to the MyMenuItems, so they''re swept away and the ruby object is deleted. Next time find_item is called, there is no Ruby object matching the found MenuItem, so it is re-wrapped as an ordinary MenuItem. This is expected behaviour - "info" type objects such as MenuItem are not preserved. I''ll have a look whether there is a way to change this without causing crashes or leaking memory, but I would suggest that you find an alternate way round this: 1) Keep a reference (eg in an Array or Hash as a member of MyMenu) to each menu item, perhaps setting this up as part of the addEntry method of MyMenu. This will preserve the items from GC. 2) Override MyMenu#find_item to return a MyMenuItem, rather than an ordinary MenuItem. hth alex
Alex Fenton wrote:> Hi > > Ridge Mcghee wrote: >> I''m subclassing menus to add an extra tag. >> However, after some repeated menu use, the menu >> item becomes corrupted. The more menu items >> there are, the more quickly the menu item becomes >> corrupted. >> >> It appears (speculation) that a garbage collector >> or some memory reclamation code is at work that >> reallocates the MyMenuItem and transforms it into >> a MenuItem. > > Hopefully I can explain. You''re right that it''s to do with garbage > collection. When Ruby''s GC runs, there''s no reference anywhere to the > MyMenuItems, so they''re swept away and the ruby object is deleted. Next > time find_item is called, there is no Ruby object matching the found > MenuItem, so it is re-wrapped as an ordinary MenuItem. > > This is expected behaviour - "info" type objects such as MenuItem are > not preserved. I''ll have a look whether there is a way to change this > without causing crashes or leaking memory, but I would suggest that you > find an alternate way round this: > > 1) Keep a reference (eg in an Array or Hash as a member of MyMenu) to > each menu item, perhaps setting this up as part of the addEntry method > of MyMenu. This will preserve the items from GC. > > 2) Override MyMenu#find_item to return a MyMenuItem, rather than an > ordinary MenuItem. > > hth > alexThanks for your response. Good suggestion (1) and that is actually what I did to move forward. However, I consider it a work-around. I welcome your explanations because I want to understand. Here''s my view: As a developer, I don''t want just the "native" superclass to work properly with the GC. I want my sub-classes to work properly, too. (e.g., my sub-class should inherit the reference count or whatever to make it a fully-qualified class, huh?) If I understood your message, the GC is making decisions based on the type (MenuItem). Isn''t this just what an object-oriented system should *not* do? Some questions: Is this a generic ruby issue (or is it unique to wxruby)? What triggers the GC ? (While testing, I found that the "rewrapping" occurred whether or not I called find_item. Just repeatedly selecting the MyMenuItem, which triggered a menu_event and caused on_menu_event to be called, would result in the MyMenuItem being "rewrapped" as a MenuItem. As such, over-riding MyMenu#find_item would not be expected to solve the problem.) I appreciate your offer to "have a look" and I''d be interested to know whatever you find out. Cheers, Ridge -- Posted via http://www.ruby-forum.com/.
Hello Ridge, Let me explain this a bit further in detail as to the process the Garbage Collector, and wxRuby''s own classes work about things. On Sun, Jan 4, 2009 at 5:22 PM, Ridge Mcghee <lists at ruby-forum.com> wrote:> Thanks for your response. > > Good suggestion (1) and that is actually what I did to move forward. > However, I consider it a work-around. I welcome your explanations > because I want to understand. > > Here''s my view: > As a developer, I don''t want just the "native" superclass to work > properly with the GC. I want my sub-classes to work properly, too. > (e.g., my sub-class should inherit the reference count or whatever > to make it a fully-qualified class, huh?) If I understood your > message, the GC is making decisions based on the type (MenuItem). > Isn''t this just what an object-oriented system should *not* do?What Alex was trying to explain here, is that some classes, such as Menu, MenuItem, Rect, Point, and various other ones, are considered Information Classes. Information classes only hold the information of what is relevent at the point and time of the execution of the code. To make it a bit more clearer to understand, let''s take the problem of MenuItem. Imagine that MenuItem is a Ruby Struct class. Defining it as such: MenuItem = Struct.new(:title,:id,:parent,:bitmap) my_new_menu_item MenuItem.new("&Open",Wx::ID_OPEN,my_file_menu,Wx::ICON_FOLDER) This is a silly mockup of what I''m trying to explain, but this is what it boils down to. Once you actually create the control, there''s no further need to reference this control, till something happens with it, such as evt_menu(Wx::ID_OPEN), this is where we re-retrive the actual wxRuby control, for any association needed to do special things, such as changing the title of the Menu item. There is no other things you can really do with a MenuItem, aside from either updating it, or deleting it. Atleast, as far as wxWidgets is concerned. Therefore, if you don''t store the instance of the MenuItem in a variable, where the Garbage Collector can see that it is still being referenced within your code, Ruby thinks that it is no longer needed, and therefore frees it up for others to use. Some questions:> Is this a generic ruby issue (or is it unique to wxruby)?This is a unique problem with wxRuby. It''s mainly a decision of what we need to continue to keep tracking, without tracking every single object created. What triggers the GC ? (While testing, I found that the "rewrapping"> occurred whether or not I called find_item. Just repeatedly > selecting > the MyMenuItem, which triggered a menu_event and caused on_menu_event > to be called, would result in the MyMenuItem being "rewrapped" as a > MenuItem. As such, over-riding MyMenu#find_item would not be > expected > to solve the problem.)Garbage Collection, especially in a wxRuby app, happens quite often, as there are many times that a Ruby object is temporarly created, to associate it with a wxWidget''s object. And 9 times out of 10, it''s a temporary reference, which is immediately de-referenced within the code, and when Garbage Collection runs again, it''ll delete this instance. However, in the particular instance of Menu Event (evt_menu), there is no particular reference to review to say, Oh, this needs to be referenced by previous instance creation. I appreciate your offer to "have a look" and I''d be interested to> know whatever you find out.Unfortunately, in this case, the procedure that Alex has referenced, would be the best way, as it would be nearly neigh improbable to track every single custom class creation, between wxWidgets and wxRuby. As with wxWidgets, there''s nothing to allow us to track custom classes created in Ruby of wxWidgets classes, least we create a new memory structure, that would inherit from one of our classes. It may be doable, in the Ruby level, at the actual Ruby level itself, but not on the C++ Side. Cheers,> Ridge > > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > wxruby-users mailing list > wxruby-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/wxruby-users >-- Mario Steele http://www.trilake.net http://www.ruby-im.net http://rubyforge.org/projects/wxruby/ http://rubyforge.org/projects/wxride/ -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/wxruby-users/attachments/20090104/40be3364/attachment-0001.html>
Mario Steele wrote:> Hello Ridge,Hi Mario, Thanks for joining the discussion. Hopefully, we can have some significant mindshare.> Let me explain this a bit further in detail as to the process the > Garbage > Collector, and wxRuby''s own classes work about things. > > On Sun, Jan 4, 2009 at 5:22 PM, Ridge Mcghee <lists at ruby-forum.com> > wrote: > >> to make it a fully-qualified class, huh?) If I understood your >> message, the GC is making decisions based on the type (MenuItem). >> Isn''t this just what an object-oriented system should *not* do? > > > What Alex was trying to explain here, is that some classes, such as > Menu, > MenuItem, Rect, Point, and various other ones, are considered > Information > Classes. Information classes only hold the information of what is > relevent > at the point and time of the execution of the code. To make it a bit > more > clearer to understand, let''s take the problem of MenuItem. Imagine that > MenuItem is a Ruby Struct class. > > Defining it as such: > > MenuItem = Struct.new(:title,:id,:parent,:bitmap) > > my_new_menu_item > MenuItem.new("&Open",Wx::ID_OPEN,my_file_menu,Wx::ICON_FOLDER) > > This is a silly mockup of what I''m trying to explain, but this is what > it > boils down to. Once you actually create the control, there''s no further > need to reference this control, till something happens with it, such as > evt_menu(Wx::ID_OPEN), this is where we re-retrive the actual wxRuby > control, for any association needed to do special things, such as > changing > the title of the Menu item. There is no other things you can really do > with > a MenuItem, aside from either updating it, or deleting it. Atleast, as > far > as wxWidgets is concerned. Therefore, if you don''t store the instance > of > the MenuItem in a variable, where the Garbage Collector can see that it > is > still being referenced within your code, Ruby thinks that it is no > longer > needed, and therefore frees it up for others to use.Your explanation is clear and I appreciate your effort to make it so. I''m hoping I can be as clear. I understand your perspective but respectfully disagree with your assertion: "There is no other things you can really do with a MenuItem, aside from either updating it, or deleting it." One of the hallmarks and most powerful aspects of an object-oriented language is that new developers are able to extend the capabilities of existing classes via subclassing (in ways that the class originators didn''t necessarily anticipate). By constraining classes in arbitrary ways (IMHO), that power is severely limited. I do understand (I think) your desire to free up memory that is not being used. However, there are already mechanisms in place: scoping rules and delete. Please help me understand why these mechanisms are not sufficient in this case. If you are providing extra GC as a convenience, then I respectfully submit that the developer should be permitted to accept or reject that convenience so that his/her code will behave as expected. By forcing extra GC upon the developer for certain classes that are considered "information classes" by the originators, the code (originally attached) behaves in a most unexpected way: On (approximately) the 25th time a class instance is used (in this case a menu appears), the (subclassed) menu items suddenly lose their identity and instead assume the identity of their superclass. Until I have the opportunity to understand your perspective more fully, I respectfully assert: Class instantiations should maintain their existence and identity until they move out of scope or until they are expressly deleted.> Some questions: >> Is this a generic ruby issue (or is it unique to wxruby)? > > > This is a unique problem with wxRuby. It''s mainly a decision of what we > need to continue to keep tracking, without tracking every single object > created.I appreciate your candidness. I''m hoping we can find a way for wxruby to be more ruby-ish.> What triggers the GC ? (While testing, I found that the "rewrapping" >> occurred whether or not I called find_item. Just repeatedly >> selecting >> the MyMenuItem, which triggered a menu_event and caused on_menu_event >> to be called, would result in the MyMenuItem being "rewrapped" as a >> MenuItem. As such, over-riding MyMenu#find_item would not be >> expected >> to solve the problem.) > > Garbage Collection, especially in a wxRuby app, happens quite often, as > there are many times that a Ruby object is temporarly created, to > associate > it with a wxWidget''s object. And 9 times out of 10, it''s a temporary > reference, which is immediately de-referenced within the code, and when > Garbage Collection runs again, it''ll delete this instance. However, in > the > particular instance of Menu Event (evt_menu), there is no particular > reference to review to say, Oh, this needs to be referenced by previous > instance creation.I understand your point that object creation is often temporary and that, with regard to Menu events, there is some difficulty in knowing what is a temporary instantiation and what is not. However, again I respectfully submit that it seems ill-advised to use probability as a solution without offering an alternative.> Unfortunately, in this case, the procedure that Alex has referenced, > would > be the best way, as it would be nearly neigh improbable to track every > single custom class creation, between wxWidgets and wxRuby. As with > wxWidgets, there''s nothing to allow us to track custom classes created > in > Ruby of wxWidgets classes, least we create a new memory structure, that > would inherit from one of our classes. It may be doable, in the Ruby > level, > at the actual Ruby level itself, but not on the C++ Side.Thank you for your trying to educate me about wxruby and for offering work-arounds that I can put in my code. I am not sure at this point why you seem so concerned about "tracking every custom class creation" when, in both C++ and ruby, subclassing is such a fundamental part of the language. There are already mechanisms available to the developer to handle memory bloat (scoping rules and express deletion of unneeded instantiations). I am very happy that you folks are working hard to support wxruby. wxruby seems to be a comprehensive, cross-platform GUI toolkit that could meet my needs. I respect your willingness to discuss issues such as the present one. I also respect your willingness to explain why you have made the decisions you have made. I hope you can also understand my surprise to be faced with such an unexpected problem on the first day of wxruby development. I want to believe that there is a solution that will meet the needs of all developers. At the risk of sounding bold, would you consider supporting the following: "wxruby fully supports subclassing, respecting scoping rules to handle object persistence. However, developers should be advised that they can unwittingly consume memory resources if they do not properly manage their objects, specifically if they do not delete objects when they are no longer needed. We have learned this through bitter experience. "Since object management can be a daunting and tedious task for the developer, wxruby provides a super-cool garbage collection facility that can automatically delete objects that are no longer referenced, significantly reducing runtime memory usage. When creating your application, simply set supercool_gc to true, as in the following example: class MyApp < App def on_init @supercool_gc = true end end "The following classes are considered ''information classes'' and will be specifically targeted by the GC: Menu MenuItem (any others) "If you subclass any of the information classes, please note that you may need to disable supercool_gc for those classes." At this point, I''m concerned that I will find other instances in which the GC will impede my development progress. But I hoping this will not be the case. It may be that the problem is limited to menu items and that the GC works beautifully in all other cases. In that case, developers would want to take advantage of the GC and would alternatively perfer to have a specific @supercool_menuitem_gc flag so that they could manage their menuitems independently but have the GC manage the rest of the objects. Or, perhaps there should be a flag for each "information class". I''m hoping we can sort this out. As noted, since I''m a wxruby newbie, I welcome further explanations to help me understand why the GC must behave as it does. I would very much like wxruby to succeed.> Cheers,Ridge -- Posted via http://www.ruby-forum.com/.
Hi Ridge Ridge Mcghee wrote:> Good suggestion (1) and that is actually what I did to move forward. >Glad that worked, and also thanks for spotting this and bringing it up.> However, I consider it a work-around. I welcome your explanations > because I want to understand. > > Here''s my view: > As a developer, I don''t want just the "native" superclass to work > properly with the GC. I want my sub-classes to work properly, too. > >I understand that, and indeed most classes where you''d want that should already do that. First up I''ll say that having seen your example, I agree that MenuItem should work correctly - ie that a custom subclass should be maintained. As you''ll have realised wxRuby is a big library with 200+ classes, and for each of them we have to select a memory management strategy. It needs 1) to be safe - ie it won''t crash under any various circumstance it''s used 2) to be efficient - it won''t leak memory, or unnecessarily slow the library (for example, GNOME2 can suffer pauses due to GC, which limits its usefulessness for real-time drawing apps) 3) to work well with Ruby''s dynamic object model 4) to work OK with wxWidgets C++ object ownership and memory management The current implementation does 1, 2 and 4 but not 3 - I simply hadn''t foreseen the use-case demonstrated by your sample.> I appreciate your offer to "have a look" and I''d be interested to > know whatever you find out.Over the weekend I made a change to my working tree. The result of this patch would be that MenuItems, once added to a Menu, would have the original object preserved. This would resolve your issue. Historically Menus and MenuItems have been among the most problematic for GC, so it''s moderately high-risk. I''m going to test it further for a few days, then commit, then we can give it some further working out on all platforms. Since you''re on Windows I''m guessing you don''t have the compiler infrastructure, in which case it''ll be available for the next 2.0 release. best alex
Hi Ridge/Mario Just read through the discussion, and think you''re both making sense. Ridge, the OO philosophy which you describe is that which I''ve had in mind developing wxRuby, and I believe we already follow in large part. This is just an implementation issue of an unforeseen use case for a particular class, which hopefully we''ve resolved for the next release. Ridge Mcghee wrote:>> What Alex was trying to explain here, is that some classes, such as >> Menu, >> MenuItem, Rect, Point, and various other ones, are considered >> Information >> Classes. Information classes only hold the information of what is >> relevent >> at the point and time of the execution of the code. To make it a bit >> more >> clearer to understand, let''s take the problem of MenuItem. Imagine that >> MenuItem is a Ruby Struct class.Just to add to Mario''s comment - indeed Size/Rect/Point are always going to be ''info'' classes and not have information added to them. This is probably clearer if you think of how they work window.size = Size.new(100, 50) # user uses application, including resizing window to 200 x 600 size = window.size # Size is now [200, 600] In this case it''s a moot point whether it''s the ''same'' size object, as its properties (size, width) are inherent to its identity. And in reality, wxWidgets doesn''t think it is, so we couldn''t return a same MySize object in Ruby. I think the need arises where one could sensibly want to add member data (ie instance variables) in a subclass. Your example demonstrated this for MenuItem, and I think it''s already covered for other classes. Indeed, I went through hoops to get this working right for some difficult cases (eg custom Event objects).> Class instantiations should maintain their existence and identity > until they move out of scope or until they are expressly deleted. >Yep, so far as the tools we have available (wxWidgets, Ruby''s GC API, SWIG etc) permit.>>> Is this a generic ruby issue (or is it unique to wxruby)?It''s an issue which any Ruby C extension library faces: how to make C/C++''s explicit alloc/free memory management interact smoothly with Ruby''s GC, whilst supporting Ruby''s highly dynamic OO scheme. It''s a particularly acute problem for long-running (eg GUI or server) libraries. As an aside, it''s also one reason that Ruby itself is a difficult language to implement efficiently - see the initial slowness of most early implementations.>> What triggers the GC ?Ruby''s GC runs whenever the size of allocated objects has reached a certain maximum heap size, and ruby is asked to allocate a new object. So from a programmer''s point of view, it''s not determined, although GC.start can be used to invoke GC explicitly.> At this point, I''m concerned that I will find other > instances in which the GC will impede my development > progress. But I hoping this will not be the case. It > may be that the problem is limited to menu items and > that the GC works beautifully in all other cases.I believe this is the case. As Mario''s mentioned, there are other classes which work like MenuItem (currently) works but I don''t think they will impede your progress. Although technically a ''beta'' release, 1.9.9 has a few years history behind it, and is one of the most widely-used GUI libraries. alex
Alex Fenton wrote:> Hi Ridge/Mario > > Just read through the discussion, and think you''re both making sense. > Ridge, the OO philosophy which you describe is that which I''ve had in > mind developing wxRuby, and I believe we already follow in large part. > > This is just an implementation issue of an unforeseen use case for a > particular class, which hopefully we''ve resolved for the next release.Great news. Thank you both for your prompt responses.> > alex-- Posted via http://www.ruby-forum.com/.