Hardcode GC coding

Started by Blizzard, March 23, 2011, 02:48:06 pm

Previous topic - Next topic

Blizzard

March 23, 2011, 02:48:06 pm Last Edit: April 07, 2011, 09:59:35 am by Blizzard
Alright, it's time for the next step. I have successfully managed to implement a Bitmap that loads a file properly. I have also made the part in Sprite work that lets it draw the Bitmap. Here comes the tricky part and you have to be careful when you code. I will explain everything.



1. Let me first explain what gc_mark and gc_free functions will be used for. The GC (garbage collector) works like this: It has a mark-phase and a collect-phase. During the mark phase it marks all objects accessible from Ruby. We have to mark C++ objects manually so the GC doesn't destroy them. Basically when an object is not marked during the mark-phase, the GC assumes that all references are lost and that it's time to delete that object. The collect-phase then simply deletes all inaccessible objects. At that moment the gc_free function is called to clean up additional stuff if necessary.



2. This is what we will use the ClassName::gc_mark function for; we will mark C++ objects that are referenced by this object. Here is a simple example:

// Sprite::rb_bitmap is of type VALUE! The reason is explained later.
void Sprite::gc_mark(Sprite* sprite)
{
   if (!NIL_P(sprite->rb_bitmap))
   {
       rb_gc_mark(sprite->rb_bitmap);
   }
}


This makes sure that the bitmap is no immediately destroyed when Ruby loses all references to that object.



3. gm_free won't be necessary in most cases. A rare case is the Bitmap class that allocates an external object. It allocates an april::Texture instance and has to get rid of it once the bitmap itself has been destroyed.



4. One of the first things I noticed is that there are problems during the GC's mark phase if you create and kind of new variable. Even though using Data_Wrap_Struct does not actually create a new object but only wraps a C++ object into a Ruby object, it seems that on the Ruby side it is considered a new object. Basically gc_mark functions crash the GC (and therefore the whole game) if Data_Wrap_Struct is called during the gc_mark call. This is one thing to keep in mind.



5. I have figured out a simple workaround for the previous problem, but it will require us to be extra careful with the code. Basically we will have to have a Ruby object reference to C++ objects in our objects. The Sprite class with the Bitmap class is a good example for that.

class Sprite
{
   Bitmap* bitmap; // C++ Bitmap object
   VALUE rb_bitmap; // Ruby Bitmap object
}


As you noticed under 2., I have been using the rb_bitmap when I was marking it for the GC. Sadly we will have to do this. I remember that RMXP was able to crash if you call GC.start at some points. That made me think a bit. I think that Enterbrain didn't do that part actually right. It even makes quite a bit of sense. I remember when I tried to implement a cache emptying functionality in CP and it would crash with an unusual error message even though all Ruby references to the bitmaps have been removed.



I'm going to post a new task after I have finalized the last few things and committed everything.

EDIT: I have also added section separations to the Color and Sprite class' source code. When you work on another class, feel free to do the same.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Blizzard

April 07, 2011, 10:00:45 am #1 Last Edit: April 07, 2011, 10:13:52 am by Blizzard
I have gotten rid of the wrap functions, they are not needed anymore.

What are we going to do about garbage collection? I can theoretically run it every time Graphics.update is called, but I think this is unwise. How long does it take RGSS to destroy a dereferenced Sprite that wasn't disposed previously?

EDIT: How often does ti take for the game to figure out a dereferenced sprite anyway?
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Ryex

supposedly ruby runs GC automatically when it detects dereferenced objects. perhaps we could have sprite increments a static class variable that stored how many sprites are disposed but not garbage collected. and the gc_free method could deincrement it. we could have the graphics update methods check if that variable was large enough and run the GC if it was.
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

ForeverZer0

I think it takes less than 5 seconds. I found this out by creating a module with a singleton method to create a window in a local variable. When the method was called in a call script, it would only show for about the length of time then disappear, presumably when the GC found that it was unreferenced and deleted it.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

I know that our Ruby doesn't ever run the GC automatically as far as I have noticed. If I dereference a sprite in the test script and run the main loop, the sprite stays there the whole time. If I run GC.start via Ruby occasionally, it gets removed, though.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Ryex

so perhaps a call to GC.start every 1-2 seconds would work.
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

Blizzard

I did that already. I put in Graphics::rb_update a call every 200 frames.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Ryex

I cant remember if we were still having problems with the GC or not but I found this.
http://stackoverflow.com/questions/12452069/embedded-ruby-gc-and-wrapped-structs
I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />

Blizzard

December 15, 2012, 06:10:08 am #8 Last Edit: December 15, 2012, 06:12:17 am by Blizzard
Yeah, I fixed it months before the beta release of the engine already.

The problem when I use xmalloc (like suggested in the post) is that it won't create proper C++ objects with virtual function tables.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Ryex

ah, well, what do you know. shows what I know.

I no longer keep up with posts in the forum very well. If you have a question or comment, about my work, or in general I welcome PM's. if you make a post in one of my threads and I don't reply with in a day or two feel free to PM me and point it out to me.<br /><br />DropBox, the best free file syncing service there is.<br />