You are viewing a plain text version of this content. The canonical link for it is here.
Posted to proton@qpid.apache.org by "Darryl L. Pierce" <dp...@redhat.com> on 2015/01/23 15:01:06 UTC

Ruby memory management (was: Ruby and the Engine APIs)

On Thu, Jan 22, 2015 at 12:08:52PM -0500, Rafael Schloming wrote:
> The most important thing to get worked out for this is the memory
> management semantics between C and Ruby. From what I can tell from your
> branch, it looks like you haven't done that yet.
<snip>

My initial readings into how Ruby handles object references initially
lead me to believe that, with Swig, we're receiving some benefit
already WRT object management. Since Ruby uses mark and sweep rather
than reference counts, when a Ruby object (or an C object wrapped by
Swig as a Ruby object) goes out of reference then it'll get garbage
collected. But I won't lie: there might be some subtle detail I'm
missing here.

I played around with this last night after your suggestion and wrote
some stuff on a side branch [1]. It's a simple test that uses the
following types:

 * pn_rubyref_t - C type in Proton that's wrapped by Swig; holds a void *
reference to any kind of object
 * Farkle - a pure Ruby class

I then wrote a simple app that creates 1M instances of rb_rubyref_t and
1M instances of Farkle as assigns a Farkle to each rb_rubyref_t. It then
puts them each into an array, which is size limited to 100k entries (to
allow any GC to run while the app is going).

I also added finalizer function to Farkle that just outputs some text when
the object is being garbage collected.

What I see as the app runs is the output of the Farkle instances being
garbage collected while there are still instances being created.

The app then ends by sleeping and then exiting.

Before and after sleeping the app outputs the number of objects (via
ObjectSpace) exist for each type. Running it multiple times I see all of
the pn_rubyref_t and Farkle instances being cleaned up, no memory
leaks.

I then changed things to make a circular reference between Farkle and
pn_rubyref_t. Re-ran the tests and still see the objects getting cleaned
up. I also ran top to keep an eye on memory usage for the ruby-mri
process.

O_o (1) [J:0/1028] mcpierce@mcpierce-laptop:cmake (0.3-fedora) $ top -b | grep ruby-mri
19989 mcpierce  20   0  188964  23228   6380 S  53.3  0.3   0:00.55 ruby-mri
19989 mcpierce  20   0  202644  36892   6380 S  18.3  0.5   0:01.10 ruby-mri
19989 mcpierce  20   0  207492  41784   6380 R  19.9  0.5   0:01.70 ruby-mri
19989 mcpierce  20   0  227748  62108   6380 S  17.6  0.8   0:02.23 ruby-mri
19989 mcpierce  20   0  229796  64020   6380 R  22.3  0.8   0:02.90 ruby-mri
19989 mcpierce  20   0  233096  67188   6380 R  57.1  0.8   0:03.42 ruby-mri
19989 mcpierce  20   0  233096  67188   6380 S   0.7  0.8   0:03.44 ruby-mri
19989 mcpierce  20   0  233096  67188   6380 S   0.0  0.8   0:03.44 ruby-mri
19989 mcpierce  20   0  233096  67188   6380 S   0.0  0.8   0:03.44 ruby-mri
19989 mcpierce  20   0  233096  67188   6380 S   1.3  0.8   0:03.48 ruby-mri
19989 mcpierce  20   0  235340  69564   6380 R  48.5  0.9   0:04.94 ruby-mri
19989 mcpierce  20   0  235340  69564   6380 S  47.5  0.9   0:06.37 ruby-mri
19989 mcpierce  20   0  235340  69564   6380 R  50.5  0.9   0:07.89 ruby-mri
19989 mcpierce  20   0  235340  69564   6380 S  48.0  0.9   0:09.34 ruby-mri

I only show those lines since, after that point, the virtual memory
footprint didn't grow for the run os the apps run.


[1] https://github.com/mcpierce/Proton/tree/c-to-ruby-reference-gc-check

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
On Fri, Jan 30, 2015 at 10:40 AM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Wed, Jan 28, 2015 at 01:22:45PM -0500, Rafael Schloming wrote:
> <snip>
> > Also, have you been able to validate your testing strategy for
> either/both
> > of these POCs? Can you generate seg faults and/or valgrind warnings when
> > you intentionally comment out the line of code that keeps the reference
> > alive?
>
> The POC that uses manual wrapping of a C struct works correctly,
> preventing objects from being reaped without leaking memory.
>
> I validated this by creating exhaustive (1M+) instances of both pure Ruby
> and C structs that have been wrapped via the Data_Wrap_Struct, assigning
> the Ruby object to the C struct so that only C held a reference to it,
> then calling GC.start to reap objects and then checking that the
> expected number of the pure Ruby objects still existed, via
> ObjectSpace.each_object([class]).count. Accessing the C-help Ruby object
> and doing functions such as class_eval on it worked without segmentation
> faults.
>
> I then ensures that it wasn't a fluke by commenting out, in the function
> that marks the Ruby object in C to keep it from being reaped, and
> re-running the tests. The app *immediately* segfaults after trying to
> class_eval the first Ruby object after garbage collection.
>
> So this path is the right one to follow.
>

This sounds promising, is there any way you could highlight the key bits to
look at on the branch you pointed to? Maybe post it in a way that would
permit line by line comments? (My git-fu isn't super strong, so if there's
already a way to do this with what you posted I apologize for the request.)

--Rafael

Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Wed, Jan 28, 2015 at 01:22:45PM -0500, Rafael Schloming wrote:
<snip> 
> Also, have you been able to validate your testing strategy for either/both
> of these POCs? Can you generate seg faults and/or valgrind warnings when
> you intentionally comment out the line of code that keeps the reference
> alive?

The POC that uses manual wrapping of a C struct works correctly,
preventing objects from being reaped without leaking memory.

I validated this by creating exhaustive (1M+) instances of both pure Ruby
and C structs that have been wrapped via the Data_Wrap_Struct, assigning
the Ruby object to the C struct so that only C held a reference to it,
then calling GC.start to reap objects and then checking that the
expected number of the pure Ruby objects still existed, via
ObjectSpace.each_object([class]).count. Accessing the C-help Ruby object
and doing functions such as class_eval on it worked without segmentation
faults.

I then ensures that it wasn't a fluke by commenting out, in the function
that marks the Ruby object in C to keep it from being reaped, and
re-running the tests. The app *immediately* segfaults after trying to
class_eval the first Ruby object after garbage collection.

So this path is the right one to follow.

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Wed, Jan 28, 2015 at 01:10:28PM -0500, Rafael Schloming wrote:
> On Wed, Jan 28, 2015 at 1:05 PM, Darryl L. Pierce <dp...@redhat.com>
> wrote:
> 
> > On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote:
> > > Why did you reject it then?
> >
> > Reject it? I don't recall rejecting any option.
> 
> I meant why did you post about the global array thing and not this. Is
> there some reason you think one is preferred to the other?

I described it since it was the one different from what we discussed
early based on the blog posts.

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
On Wed, Jan 28, 2015 at 1:05 PM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote:
> > Why did you reject it then?
>
> Reject it? I don't recall rejecting any option.
>

I meant why did you post about the global array thing and not this. Is
there some reason you think one is preferred to the other?

--Rafael

Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote:
> Why did you reject it then?

Reject it? I don't recall rejecting any option.

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
No, you posted about a POC involving keeping C references alive by putting
them in a global array. I then commented that it sounded like it could be
brittle and might be more complicated than just wrapping the pn_rubyref_t
struct manually and directly integrating with ruby gc. You then said you
had a POC that did that also. Is there a reason you didn't mention the
latter POC first? Which POC is better in your estimation and why?

Also, have you been able to validate your testing strategy for either/both
of these POCs? Can you generate seg faults and/or valgrind warnings when
you intentionally comment out the line of code that keeps the reference
alive?

--Rafael


On Wed, Jan 28, 2015 at 1:12 PM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote:
> > Why did you reject it then?
>
> Are you referring to this?
>
> "Though, I was hoping we could avoid having to manually do things..."
>
> What I meant was that I would like to keep the work within the confines
> of the Swig code.
>
> --
> Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
> Delivering value year after year.
> Red Hat ranks #1 in value among software vendors.
> http://www.redhat.com/promo/vendor/
>
>

Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Wed, Jan 28, 2015 at 12:06:44PM -0500, Rafael Schloming wrote:
> Why did you reject it then?

Are you referring to this?

"Though, I was hoping we could avoid having to manually do things..."

What I meant was that I would like to keep the work within the confines
of the Swig code.

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
Why did you reject it then?

--Rafael

On Wed, Jan 28, 2015 at 9:54 AM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Wed, Jan 28, 2015 at 09:19:29AM -0500, Rafael Schloming wrote:
> > On Wed, Jan 28, 2015 at 9:06 AM, Darryl L. Pierce <dp...@redhat.com>
> > wrote:
> >
> > > On Wed, Jan 28, 2015 at 06:04:57AM -0500, Rafael Schloming wrote:
> > > > On the face of it this sounds like it could be quite brittle and
> probably
> > > > more complicated than just forgetting about swig for the one
> pn_rubyref_t
> > > > struct and wrapping it manually. Did you attempt the latter option at
> > > all?
> > >
> > > Yes, there is a POC of this on my branch as well.
> > >
> >
> > Did it work? Can you send me a pointer to it?
>
> Yes, it works. It uses Data_Wrap_Struct to encapsulate the pn_rubyref_t
> type, rb_gc_mark to mark any Ruby object held by that type against
> reaping, and does appropriate alloc and free operations on instances of
> the struct.
>
> https://github.com/mcpierce/Proton/tree/c-to-ruby-reference-gc-check
>
> --
> Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
> Delivering value year after year.
> Red Hat ranks #1 in value among software vendors.
> http://www.redhat.com/promo/vendor/
>
>

Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Wed, Jan 28, 2015 at 09:19:29AM -0500, Rafael Schloming wrote:
> On Wed, Jan 28, 2015 at 9:06 AM, Darryl L. Pierce <dp...@redhat.com>
> wrote:
> 
> > On Wed, Jan 28, 2015 at 06:04:57AM -0500, Rafael Schloming wrote:
> > > On the face of it this sounds like it could be quite brittle and probably
> > > more complicated than just forgetting about swig for the one pn_rubyref_t
> > > struct and wrapping it manually. Did you attempt the latter option at
> > all?
> >
> > Yes, there is a POC of this on my branch as well.
> >
> 
> Did it work? Can you send me a pointer to it?

Yes, it works. It uses Data_Wrap_Struct to encapsulate the pn_rubyref_t
type, rb_gc_mark to mark any Ruby object held by that type against
reaping, and does appropriate alloc and free operations on instances of
the struct.

https://github.com/mcpierce/Proton/tree/c-to-ruby-reference-gc-check

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
On Wed, Jan 28, 2015 at 9:06 AM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Wed, Jan 28, 2015 at 06:04:57AM -0500, Rafael Schloming wrote:
> > On the face of it this sounds like it could be quite brittle and probably
> > more complicated than just forgetting about swig for the one pn_rubyref_t
> > struct and wrapping it manually. Did you attempt the latter option at
> all?
>
> Yes, there is a POC of this on my branch as well.
>

Did it work? Can you send me a pointer to it?

--Rafael

Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Wed, Jan 28, 2015 at 06:04:57AM -0500, Rafael Schloming wrote:
> On the face of it this sounds like it could be quite brittle and probably
> more complicated than just forgetting about swig for the one pn_rubyref_t
> struct and wrapping it manually. Did you attempt the latter option at all?

Yes, there is a POC of this on my branch as well. 

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
On Tue, Jan 27, 2015 at 5:35 PM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Fri, Jan 23, 2015 at 03:46:34PM -0500, Darryl L. Pierce wrote:
> > +1 Though, I was hoping we could avoid having to manually do things...
>
> So I have a working POC that assigns a Ruby object to a C struct in such
> a way as to keep the Ruby object from being reaped. The solution (for
> now) stores the object in a hidden global array for such objects for as
> long as they're held by the C structure and, when C is deleted or the
> reference changed, the object is removed from the array and available
> for reaping.
>
> I submitted a question to the Swig users mailing list, but that seems to
> be pretty low traffic and effectively unmanned ATM. Only 15 posts there
> in the last month and none of them have followups.
>

On the face of it this sounds like it could be quite brittle and probably
more complicated than just forgetting about swig for the one pn_rubyref_t
struct and wrapping it manually. Did you attempt the latter option at all?

It's really important to get this part right. If this isn't done well, then
the whole binding will be unstable. Whatever has been done here with the
current ruby bindings seems to seg fault about once every 10 test runs or
so. We really can't afford to repeat that.

--Rafael

Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Fri, Jan 23, 2015 at 03:46:34PM -0500, Darryl L. Pierce wrote:
> +1 Though, I was hoping we could avoid having to manually do things...

So I have a working POC that assigns a Ruby object to a C struct in such
a way as to keep the Ruby object from being reaped. The solution (for
now) stores the object in a hidden global array for such objects for as
long as they're held by the C structure and, when C is deleted or the
reference changed, the object is removed from the array and available
for reaping.

I submitted a question to the Swig users mailing list, but that seems to
be pretty low traffic and effectively unmanned ATM. Only 15 posts there
in the last month and none of them have followups.

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Fri, Jan 23, 2015 at 03:25:33PM -0500, Rafael Schloming wrote:
> On Fri, Jan 23, 2015 at 2:08 PM, Darryl L. Pierce <dp...@redhat.com>
> wrote:
> 
> > On Fri, Jan 23, 2015 at 01:49:34PM -0500, Rafael Schloming wrote:
> > > It does talk about what swig does, but it also talks about the other
> > > direction:
> > >
> > > "If the C structure references other ruby objects, then the mark function
> > > pointer must also be provided and must properly mark the other objects
> > with
> > > rb_gc_mark()"
> >
> > What I meant is it's not showing how to do that. Swig is the one that's
> > generating that Ruby struct wrapping, but I haven't found (yet) if they
> > expose to users a way to tap into that adn do what we want.
> >
> 
> If you can find a way for swig to let you control it that's great, but I
> was thinking we could just wrap this one struct by hand. It shouldn't be a
> whole lot of code for just that struct, and swig can still handle the rest
> of them.

+1 Though, I was hoping we could avoid having to manually do things...

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
On Fri, Jan 23, 2015 at 2:08 PM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Fri, Jan 23, 2015 at 01:49:34PM -0500, Rafael Schloming wrote:
> > It does talk about what swig does, but it also talks about the other
> > direction:
> >
> > "If the C structure references other ruby objects, then the mark function
> > pointer must also be provided and must properly mark the other objects
> with
> > rb_gc_mark()"
>
> What I meant is it's not showing how to do that. Swig is the one that's
> generating that Ruby struct wrapping, but I haven't found (yet) if they
> expose to users a way to tap into that adn do what we want.
>

If you can find a way for swig to let you control it that's great, but I
was thinking we could just wrap this one struct by hand. It shouldn't be a
whole lot of code for just that struct, and swig can still handle the rest
of them.

--Rafael

Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Fri, Jan 23, 2015 at 01:49:34PM -0500, Rafael Schloming wrote:
> It does talk about what swig does, but it also talks about the other
> direction:
> 
> "If the C structure references other ruby objects, then the mark function
> pointer must also be provided and must properly mark the other objects with
> rb_gc_mark()"

What I meant is it's not showing how to do that. Swig is the one that's
generating that Ruby struct wrapping, but I haven't found (yet) if they
expose to users a way to tap into that adn do what we want.

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
It does talk about what swig does, but it also talks about the other
direction:

"If the C structure references other ruby objects, then the mark function
pointer must also be provided and must properly mark the other objects with
rb_gc_mark()"

--Rafael


On Fri, Jan 23, 2015 at 1:24 PM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Fri, Jan 23, 2015 at 11:02:59AM -0500, Rafael Schloming wrote:
> <snip>
> > For more info on how to integrate with Ruby's GC you can read this
> > article[1]. It's one of the few pieces of documentation I've found that
> > actually explain how to keep a reference from C to a Ruby object.
> >
> > [1]
> >
> http://clalance.blogspot.com/2013/11/writing-ruby-extensions-in-c-part-13.html
>
> This blog post shows how to manually do what Swig is doing for us:
> represent a C struct as something Ruby can touch, with hooks to release
> memory when GC runs on the Ruby wrapper. But, sadly, it's not showing
> what we need, which is how to assign a reference to a Ruby object to a C
> struct and then have Ruby not GC that Ruby object.
>
> --
> Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
> Delivering value year after year.
> Red Hat ranks #1 in value among software vendors.
> http://www.redhat.com/promo/vendor/
>
>

Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by "Darryl L. Pierce" <dp...@redhat.com>.
On Fri, Jan 23, 2015 at 11:02:59AM -0500, Rafael Schloming wrote:
<snip> 
> For more info on how to integrate with Ruby's GC you can read this
> article[1]. It's one of the few pieces of documentation I've found that
> actually explain how to keep a reference from C to a Ruby object.
> 
> [1]
> http://clalance.blogspot.com/2013/11/writing-ruby-extensions-in-c-part-13.html

This blog post shows how to manually do what Swig is doing for us:
represent a C struct as something Ruby can touch, with hooks to release
memory when GC runs on the Ruby wrapper. But, sadly, it's not showing
what we need, which is how to assign a reference to a Ruby object to a C
struct and then have Ruby not GC that Ruby object.

-- 
Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
Delivering value year after year.
Red Hat ranks #1 in value among software vendors.
http://www.redhat.com/promo/vendor/


Re: Ruby memory management (was: Ruby and the Engine APIs)

Posted by Rafael Schloming <rh...@alum.mit.edu>.
That sounds like progress, but from what you're describing I'm not sure
you're actually testing C holding onto a reference to Ruby. As you say,
swig is helping you out with the Ruby -> C direction, but we need to be
able to make that void * reference actually point to a ruby object (that is
not pointed to by any other ruby object) and still keep it alive. If you
haven't had to integrate with the ruby GC system yet then there is a pretty
good chance you aren't actually testing this. It can be a bit tricky to
test for a couple reasons since a) you need to force the GC to run, and b)
you need to ensure there are no other references to the ruby object that is
being pointed to by the C object.

In fact now that I think about it, you really probably want a negative test
to ensure that your testing strategy is working, i.e. keep tweaking your
test until you get valgrind warnings telling you that you're accessing
freed memory. Then enable the GC integration, and verify that those
valgrind warnings go away.

For more info on how to integrate with Ruby's GC you can read this
article[1]. It's one of the few pieces of documentation I've found that
actually explain how to keep a reference from C to a Ruby object.

[1]
http://clalance.blogspot.com/2013/11/writing-ruby-extensions-in-c-part-13.html

--Rafael

On Fri, Jan 23, 2015 at 9:01 AM, Darryl L. Pierce <dp...@redhat.com>
wrote:

> On Thu, Jan 22, 2015 at 12:08:52PM -0500, Rafael Schloming wrote:
> > The most important thing to get worked out for this is the memory
> > management semantics between C and Ruby. From what I can tell from your
> > branch, it looks like you haven't done that yet.
> <snip>
>
> My initial readings into how Ruby handles object references initially
> lead me to believe that, with Swig, we're receiving some benefit
> already WRT object management. Since Ruby uses mark and sweep rather
> than reference counts, when a Ruby object (or an C object wrapped by
> Swig as a Ruby object) goes out of reference then it'll get garbage
> collected. But I won't lie: there might be some subtle detail I'm
> missing here.
>
> I played around with this last night after your suggestion and wrote
> some stuff on a side branch [1]. It's a simple test that uses the
> following types:
>
>  * pn_rubyref_t - C type in Proton that's wrapped by Swig; holds a void *
> reference to any kind of object
>  * Farkle - a pure Ruby class
>
> I then wrote a simple app that creates 1M instances of rb_rubyref_t and
> 1M instances of Farkle as assigns a Farkle to each rb_rubyref_t. It then
> puts them each into an array, which is size limited to 100k entries (to
> allow any GC to run while the app is going).
>
> I also added finalizer function to Farkle that just outputs some text when
> the object is being garbage collected.
>
> What I see as the app runs is the output of the Farkle instances being
> garbage collected while there are still instances being created.
>
> The app then ends by sleeping and then exiting.
>
> Before and after sleeping the app outputs the number of objects (via
> ObjectSpace) exist for each type. Running it multiple times I see all of
> the pn_rubyref_t and Farkle instances being cleaned up, no memory
> leaks.
>
> I then changed things to make a circular reference between Farkle and
> pn_rubyref_t. Re-ran the tests and still see the objects getting cleaned
> up. I also ran top to keep an eye on memory usage for the ruby-mri
> process.
>
> O_o (1) [J:0/1028] mcpierce@mcpierce-laptop:cmake (0.3-fedora) $ top -b |
> grep ruby-mri
> 19989 mcpierce  20   0  188964  23228   6380 S  53.3  0.3   0:00.55
> ruby-mri
> 19989 mcpierce  20   0  202644  36892   6380 S  18.3  0.5   0:01.10
> ruby-mri
> 19989 mcpierce  20   0  207492  41784   6380 R  19.9  0.5   0:01.70
> ruby-mri
> 19989 mcpierce  20   0  227748  62108   6380 S  17.6  0.8   0:02.23
> ruby-mri
> 19989 mcpierce  20   0  229796  64020   6380 R  22.3  0.8   0:02.90
> ruby-mri
> 19989 mcpierce  20   0  233096  67188   6380 R  57.1  0.8   0:03.42
> ruby-mri
> 19989 mcpierce  20   0  233096  67188   6380 S   0.7  0.8   0:03.44
> ruby-mri
> 19989 mcpierce  20   0  233096  67188   6380 S   0.0  0.8   0:03.44
> ruby-mri
> 19989 mcpierce  20   0  233096  67188   6380 S   0.0  0.8   0:03.44
> ruby-mri
> 19989 mcpierce  20   0  233096  67188   6380 S   1.3  0.8   0:03.48
> ruby-mri
> 19989 mcpierce  20   0  235340  69564   6380 R  48.5  0.9   0:04.94
> ruby-mri
> 19989 mcpierce  20   0  235340  69564   6380 S  47.5  0.9   0:06.37
> ruby-mri
> 19989 mcpierce  20   0  235340  69564   6380 R  50.5  0.9   0:07.89
> ruby-mri
> 19989 mcpierce  20   0  235340  69564   6380 S  48.0  0.9   0:09.34
> ruby-mri
>
> I only show those lines since, after that point, the virtual memory
> footprint didn't grow for the run os the apps run.
>
>
> [1] https://github.com/mcpierce/Proton/tree/c-to-ruby-reference-gc-check
>
> --
> Darryl L. Pierce, Sr. Software Engineer @ Red Hat, Inc.
> Delivering value year after year.
> Red Hat ranks #1 in value among software vendors.
> http://www.redhat.com/promo/vendor/
>
>