我将Ruby 2.2嵌入到C ++应用程序中并尝试优化表单的功能
VALUE toRubyString( const MyObject &o )
{
const char *utf8 = get_string_rep_of( o );
return rb_enc_str_new( utf8, strlen( utf8 ), rb_utf8_encoding() );
}
事实证明,在某些用例中,toRubyString
支配运行时分析输出。在这些情况下,函数会被频繁调用,但只有几个不同的MyObject
值。因此,我的想法是将VALUE
值缓存在std::map<MyObject, VALUE>
之类,以便我可以重复使用它们,
std::map<MyObject, VALUE> cache;
VALUE toRubyString( const MyObject &o )
{
std::map<MyObject, VALUE>::const_iterator it = cache.find( o );
if ( it != cache.end() ) {
return it->second;
}
const char *utf8 = get_string_rep_of( o );
VALUE v = rb_enc_str_new( utf8, strlen( utf8 ), rb_utf8_encoding() );
cache[o] = v;
return v;
}
唉,我注意到通过这个修改,Ruby解释器最终崩溃了,如果我省略return it->second;
行,那么崩溃就会消失(即当代码避免重用缓存的条目时)。
我怀疑这与垃圾收集器有关,因为它只发生在几千次调用函数之后,甚至是
rb_gc_mark(v);
调用(在将VALUE
添加到缓存之前)没有帮助。有没有人知道我在这里可能缺少什么?
答案 0 :(得分:1)
rb_global_variable(&cache[o])
可能会工作。
Apparently,插入地图不应该使指向现有元素的指针无效,所以在技术上可以像这样使用地图值的地址。然后rb_global_variable
将使得缓存的值完全从GC中排除。
rb_gc_mark
不起作用的原因是因为这只会阻止在 next 集合上清除对象。您通常在定义custom class's mark function时使用它,以便GC可以适当地标记内部引用的对象。