Ruby C gem 运行之间的内存污染

Ruby C gem memory pollution between runs

我用 C 写了一个 gem,它似乎在运行之间保持污染的内存。

我过去曾注意到这一点,但最终发现如何通过使用 Spring 调用 RSpec 中的 Gem 来一致地重现它。当运行这个单例RSpec重启后Spring,这个例子总是通过。但是没有重新启动 Spring 的后续运行会导致垃圾数据。进一步的后续运行导致 相同 垃圾数据。

示例:

$ spring stop
Spring stopped.
$ spring rspec ..._spec.rb:122
...
1 example, 0 failures

$ spring rspec ..._spec.rb:122
...
Failures:
...
       expected collection contained:  [7]
       actual collection contained:    [1333155159]
$ spring rspec ..._spec.rb:122
...
Failures:
...
       expected collection contained:  [7]
       actual collection contained:    [1333155159]

$ spring stop
Spring stopped.
$ spring rspec ..._spec.rb:122
...
1 example, 0 failures

$ spring rspec ..._spec.rb:122
...
Failures:
...
       expected collection contained:  [7]
       actual collection contained:    [117372691]
$ spring rspec ..._spec.rb:122
...
Failures:
...
       expected collection contained:  [7]
       actual collection contained:    [117372691]

C 不应在运行之间保留任何内容。唯一的全局声明是常量、结构定义、函数和模块名称本身。例如(简化为每种类型的声明中只有一个,headers 除外):

#include <ruby.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define SOME_CONSTANTS 100

struct some_structs {
  long id;
  double amount;
};

static long some_functions();

VALUE MyModuleName = Qnil;
VALUE internal_function_name(VALUE self, VALUE rb_data, VALUE rb_options);

void Init_my_gem() {
  MyModuleName = rb_define_module("MyModuleName");
  rb_define_singleton_method(MyModuleName, "exposed_function_name",
    internal_function_name, 2);
}

感谢您对正在发生的事情的任何想法。

编辑

我把它隔离到这个:

printf("A orders[0].products[0]->id: %lu\n", orders[0].products[0]->id);
VALUE rb_best_orders = rb_ary_new();
printf("B orders[0].products[0]->id: %lu\n", orders[0].products[0]->id);

Output:
A orders[0].products[0]->id: 7
B orders[0].products[0]->id: 140735021913496

注意 orders 被定义为 struct order *orders;,它的内存是通过 malloc 获取的。

已使用 ALLOC_N 而不是 malloc 修复。 http://clalance.blogspot.com/2011/01/writing-ruby-extensions-in-c-part-12.html 很有帮助,尽管它说 malloc 应该可以工作。