The last question about rb_gc_register_address(): a case in which in works with dynamic memory

Hi, what I understand (after some useful threads in this mailist)
about rb_gc_register_address() is that it’s only valid for fixed
memory (in the stack). So if for example I have a global/static VALUE
in my MyLibrary_init() function, I should use it to avoid GC (it’s not
referenced by any other Ruby object in Ruby land):


static VALUE string_Via;

void MyLibrary_init(void) {
some_string = rb_str_new2(“HELLO WORLS”);

  // If I don't do this, it will be GC'd:
  rb_gc_register_address(&some_string);

}

But I cannot use rb_global_variable(), for example, to avoid GC for a
VALUE object passed as function parameter since I’m trying to register
its memory address, which would get invalidated after the function
and when the variable gets out of the Ruby scope.

Ok, it makes sense. But I’ve found a way to make it to work and would
like to share it (to know if it’s a risk or it just works in certain
cases):


struct data_struct {
VALUE data;
int lalala;
long lololo;
}

VALUE MyLibrary_some_method(VALUE self, VALUE data)
{
struct data_struct* my_data_struct = ALLOC(struct data_struct);

my_data_struct->data = data;

// This WONT avoid GC:
// rb_gc_register_address(&data);

// But this WILL avoid GC:
rb_gc_register_address(&(my_data_struct->data));
}

The memory address for which I’m calling rb_register_address() is
allocated by me, and I will not free it for now. And before freeing it
I will call rb_gc_unregister_address(&(my_data_struct->data)), so it
“should” be safe.

So, could somebody confirm me that the above is a correct usage of
rb_gc_register_address()? As said before, in my tests it works (it
avoids GC).

BTW I would also like to know whether both rb_gc_register_address()
and rb_gc_unregister_address() can be called without the GVL.

Really thanks a lot.

PS: I’m already using rb_gc_mark() when the VALUE is attached to the C
struct wrapped within a Ruby object, that’s ok. But I “need” the above
usage for the case of C data holding Ruby objects, without such a C
data being “mapped” to a Ruby object.

2012/5/30 Iñaki Baz C. [email protected]:

So, could somebody confirm me that the above is a correct usage of
rb_gc_register_address()? As said before, in my tests it works (it
avoids GC).

I’ve found an article which talks about this:
http://metaeditor.sourceforge.net/embed/

But I don’t agree when it says:

“The rb_gc_register_address function is calling ALLOC every time and
is thus very slow. Lucky us we have a faster alternative: keeping
track of all our objects in an array (or hash). This reduces the
number of allocations, which give us speed.”

I’m pretty sure that, when adding an object to an Array or Hash, Ruby
MUST perform malloc/ALLOC, so no difference here.

The article aslo says that:

    objects = rb_ary_new();
    rb_gc_register_address(&objects);

“What happens if GC runs between [objects = rb_ary_new()] and
rb_gc_register_address(&objects); ? Or can this never happen?
Yes, AFAIK this can happen, but only in special cases
(TODO which cases?).”

I really hope this is NOT possible. If not we are lost. This is, if I
create a VALUE in C land it cannot be GC’d in next C function. Hope
I’m right here.

“Iñaki Baz C.” [email protected] wrote in post #1062693:

    objects = rb_ary_new();
    rb_gc_register_address(&objects);

I really hope this is NOT possible. If not we are lost. This is, if I
create a VALUE in C land it cannot be GC’d in next C function. Hope
I’m right here.

Hi,

A long time ago (probably ten years ago) I got a reply from Matz that if
‘objects’ is on the stack, then it is protected (i.e., it will not be
GC’ed).

Regards,

Bill

2012/5/31 Admin T. [email protected]:

A long time ago (probably ten years ago) I got a reply from Matz that if
‘objects’ is on the stack, then it is protected (i.e., it will not be
GC’ed).

Thanks, it makes sense. Otherwise Houston we have a problem!:

// Create an Array.
VALUE my_array = rb_ary_new();

// GC works here and GC’s my_arary…

// Store it in some Hash to avoid GC.
rb_hash_aset(my_hash, some_key, my_array);

// BANG !!!

Obviously it cannot not be possible :slight_smile: