浏览 1843 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-06-04
最后修改:2009-06-04
目的:建立 ruby 对象和 C 结构之间的关系
一种方法是用一个实例变量来存储结构对象的指针。例如: rb_iv_set(rb_obj, "@ptr", LONG2NUM((long)ptr)) 问题在于 @ptr 是 ruby 可以访问的,不知内情的人如果碰了它,就很容易出来一个 segmentfault(非法内存地址)。 而且指针在 32 位的系统里是 long,但在 8 字节系统里却是 long long,得把 LONG2NUM 改成 ll2NUM。 另一种方法是用 ruby 提供的 Data_Wrap_Struct 宏。 Data_Wrap_Struct 在 ruby 里 new 出一个对象,这个对象隐式捆绑一个 C 结构的指针……所谓隐式,就是 ruby 中无法访问,让人安心…… Ruby V1.9 C Extension 写道 Encapsulate C data into Ruby object To wrap and objectify a C pointer as a Ruby object (so called DATA), use Data_Wrap_Struct(). Data_Wrap_Struct(klass, mark, free, ptr) Data_Wrap_Struct() returns a created DATA object. The klass argument is the class for the DATA object. The mark argument is the function to mark Ruby objects pointed by this data. The free argument is the function to free the pointer allocation. If this is -1, the pointer will be just freed. The functions mark and free will be called from garbage collector. You can allocate and wrap the structure in one step. Data_Make_Struct(klass, type, mark, free, sval) This macro returns an allocated Data object, wrapping the pointer to the structure, which is also allocated. This macro works like: (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval)) Arguments klass, mark, and free work like their counterparts in Data_Wrap_Struct(). A pointer to the allocated structure will be assigned to sval, which should be a pointer of the type specified. To retrieve the C pointer from the Data object, use the macro Data_Get_Struct(). Data_Get_Struct(obj, type, sval) A pointer to the structure will be assigned to the variable sval. 补充解释一些参数: klass:对应的 ruby 类(C 内类型是 VALUE)。 mark :标记函数,一般用来让这个对象不会被 gc 扫除掉。典型写法是 void markf(cstruct_type *ptr) { rb_gc_mark(ptr->related_val);} sval :对应的 C 结构 (cstruct_type) 指针。sval 是设值型参数。 free : gc 删除该对象时的回调函数,典型写法是 void freef(cstruct_type *ptr) { delete ptr;} Speed Issues rb_gc_mark 包含一次内存分配(你干嘛还 alloc 啊……),也是非常慢的操作。 提升 rb_gc_mark 的速度,可以用一个已 mark 的数组或者 hash 保存对象,只要有引用指向了这个对象,就会添加一个 mark,而这种天然 mark 过程不包含 alloc 操作…… ruby embedded into c++ 写道 class Objects { private: VALUE objects; public: Objects() { objects = rb_ary_new(); rb_gc_register_address(&objects); } ~Objects() { // dispose array and flush all elements rb_gc_unregister_address(&objects); /* mass destruction. GC can no longer mark the elements in the Array and therefore they will all get swept. */ } void Register(VALUE object) { rb_ary_push(objects, object); } void Unregister(VALUE object) { rb_ary_delete(objects, object); } }; 同样由于每次调用都会分配内存,应该尽量避免 Data_Make_Struct。 提速方法A: 使用局部变量或者用 ALLOCA / ALLOCA_N 在栈内分配 struct 的内存,出栈的时候自然会 free 掉。栈内存分配比 ALLOC、malloc 和默认 new 运算符快多了。 提速方法B: 自定义该结构的 Allocator 或者 new 操作符,一次分配一大块内存,用的时候按格子分。(类似于 Pool Allocator)。对小型、定长、大量对象非常有效。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |