I'm writing a Ruby extension wrapping a library that uses talloc for its
memory allocation. I'm trying to make ruby's gc play nice with
it. Here's a summary of the extension objects I'm dealing with:
Database (the main object)
Directory (returned by a method of Database)
FileNames (returned by a method of Directory)
Query (returned by a method of Database)
Threads (returned by a method of Query)
Thread (returned by a method of Threads)
Messages (returned by a method of either Query or Threads or Thread)
Message (returned by a method of either Database or Messages)
Tags (returned by a method of either Thread or Message or Messages)
The problem is when the parent of an object is freed, the object is
freed automatically as well. For example when a Threads object is freed,
all the Thread objects that belong to it are freed automatically. This
means when the Database is freed all, or closed by the user, the
underlying objects are freed automatically by talloc. This means an
object may only be freed if its parent hasn't been freed yet.
So far so good, to make ruby's gc play nice with this way of allocation,
every struct that represents an object has an element VALUE parent and
it's marked using rb_gc_mark(object->parent) in the mark phase.
This problem arises when e.g. I have a database and message object and
both of them go out of scope. Ruby-1.8 frees the message first and then
the database but Ruby-1.9 does the opposite thus my extension blows.
How can I ensure the objects are freed in order, from children to parent?
You'll need to impose the order in your free functions. You can't depend on even ruby 1.8 to free the items in the proper order by itself.
···
On May 24, 2010, at 22:55, Ali Polatel wrote:
The problem is when the parent of an object is freed, the object is
freed automatically as well. For example when a Threads object is freed,
all the Thread objects that belong to it are freed automatically. This
means when the Database is freed all, or closed by the user, the
underlying objects are freed automatically by talloc. This means an
object may only be freed if its parent hasn't been freed yet.
So far so good, to make ruby's gc play nice with this way of allocation,
every struct that represents an object has an element VALUE parent and
it's marked using rb_gc_mark(object->parent) in the mark phase.
This problem arises when e.g. I have a database and message object and
both of them go out of scope. Ruby-1.8 frees the message first and then
the database but Ruby-1.9 does the opposite thus my extension blows.
How can I ensure the objects are freed in order, from children to parent?
Adding to that: relying on destruction order is a thing that typically
comes from the C++ world [1] but even there this idiom can only be
used for instances on the stack. I believe, this C++ heritage has
made people forget that memory (de)allocation and state
initialization/destruction are *two separate things*. In Ruby, this
is made obvious by the fact that classes do not define a destructor
(and a few other details, for example method Class#alloc). In other
words, you cannot rely on memory deallocation (aka GC) for state
destruction. Instead you have to do that explicitly.
In Ruby, if you want to maintain proper ordering of resource
(de)allocation you would typically use "ensure" part of blocks (either
explicitly or implicitly in a method accepting a block like File.open
with block does). Example for explicit usage:
a = create_a
begin
b = a.create_b
begin
b.use
ensure
b.release
end
ensure
a.release
end
Ali, you can find a bit more in my blog post at
http://blog.rubybestpractices.com/posts/rklemme/002_Writing_Block_Methods.html
and the other posts before and after it.
Kind regards
robert
[1] http://www.c2.com/cgi/wiki$?ResourceAllocationIsInitialization
···
2010/5/26 Eric Hodel <drbrain@segment7.net>:
On May 24, 2010, at 22:55, Ali Polatel wrote:
The problem is when the parent of an object is freed, the object is
freed automatically as well. For example when a Threads object is freed,
all the Thread objects that belong to it are freed automatically. This
means when the Database is freed all, or closed by the user, the
underlying objects are freed automatically by talloc. This means an
object may only be freed if its parent hasn't been freed yet.
So far so good, to make ruby's gc play nice with this way of allocation,
every struct that represents an object has an element VALUE parent and
it's marked using rb_gc_mark(object->parent) in the mark phase.
This problem arises when e.g. I have a database and message object and
both of them go out of scope. Ruby-1.8 frees the message first and then
the database but Ruby-1.9 does the opposite thus my extension blows.
How can I ensure the objects are freed in order, from children to parent?
You'll need to impose the order in your free functions. You can't depend on even ruby 1.8 to free the items in the proper order by itself.
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
>> The problem is when the parent of an object is freed, the object is
>> freed automatically as well. For example when a Threads object is freed,
>> all the Thread objects that belong to it are freed automatically. This
>> means when the Database is freed all, or closed by the user, the
>> underlying objects are freed automatically by talloc. This means an
>> object may only be freed if its parent hasn't been freed yet.
>>
>> So far so good, to make ruby's gc play nice with this way of allocation,
>> every struct that represents an object has an element VALUE parent and
>> it's marked using rb_gc_mark(object->parent) in the mark phase.
>>
>> This problem arises when e.g. I have a database and message object and
>> both of them go out of scope. Ruby-1.8 frees the message first and then
>> the database but Ruby-1.9 does the opposite thus my extension blows.
>>
>> How can I ensure the objects are freed in order, from children to parent?
>
> You'll need to impose the order in your free functions. You can't depend on even ruby 1.8 to free the items in the proper order by itself.
Adding to that: relying on destruction order is a thing that typically
comes from the C++ world [1] but even there this idiom can only be
used for instances on the stack. I believe, this C++ heritage has
made people forget that memory (de)allocation and state
initialization/destruction are *two separate things*. In Ruby, this
is made obvious by the fact that classes do not define a destructor
(and a few other details, for example method Class#alloc). In other
words, you cannot rely on memory deallocation (aka GC) for state
destruction. Instead you have to do that explicitly.
In Ruby, if you want to maintain proper ordering of resource
(de)allocation you would typically use "ensure" part of blocks (either
explicitly or implicitly in a method accepting a block like File.open
with block does). Example for explicit usage:
a = create_a
begin
b = a.create_b
begin
b.use
ensure
b.release
end
ensure
a.release
end
Thanks for the descriptive response, now it's all clear 
Ali, you can find a bit more in my blog post at
http://blog.rubybestpractices.com/posts/rklemme/002_Writing_Block_Methods.html
and the other posts before and after it.
Looks really helpful, thanks!
···
On Wed, 26 May 2010 16:55:47 +0900, Robert Klemme <shortcutter@googlemail.com> wrote:
2010/5/26 Eric Hodel <drbrain@segment7.net>:
> On May 24, 2010, at 22:55, Ali Polatel wrote:
Kind regards
robert
--
Regards,
Ali Polatel