Как маркировка должна выполняться на массивах VALUE * в расширении Ruby? - PullRequest
2 голосов
/ 13 марта 2012

У меня есть матричный тип, который содержит массив void*, представляющий массив объектов (которые относятся к одному типу в данной матрице, например, все целые числа C, все числа с плавающей запятой, двойные числа, различные структуры иливозможно даже все Ruby VALUE s).

Распределение памяти и сборка мусора, кажется, работают правильно, пока я не попытаюсь создать матрицу из VALUE s.

У меня есть следующая функция пометкиопределено:

void mark_dense_storage(void* s) {
  size_t i;
  DENSE_STORAGE* storage = (DENSE_STORAGE*)s;
  if (storage && storage->dtype == RUBY_OBJECT)
    for (i = 0; i < count_dense_storage_elements(s); ++i)
      rb_gc_mark(*((VALUE*)(storage->elements + i*sizeof(VALUE)));
}

Таким образом, маркировка выполняется только в том случае, если это матрица VALUE, в противном случае NULL передается в Data_Wrap_Struct для функции маркировки.

Но я 'я получаю segfault, когда я тестирую некоторые VALUE матричные функции (см. суть) .

В частности, кажется, что segfault при первом вызове метода Ruby всамый первый объект в массиве VALUE*:

C[i+j*ldc] = rb_funcall(C[i+j*ldc], nm_id_mult, 1, beta); // C[i+j*ldc] = C[i+j*ldc]*beta

nm_id_mult - это глобальный объект, определенный в моей функции Init как rb_intern("*").

Возможно, это непроблема сбора мусора, но GC - это часть Ruby, которую я понимаюпо крайней мере - и мой segfault также почти идентичен этому следу , который плакат приписывает GC.

Итак, мои вопросы:

  1. Если это GC, как правильно пометить массив VALUE с?

  2. Если это не GC, как мне диагностировать этот тип ошибки?Я никогда не видел ничего подобного.

РЕДАКТИРОВАТЬ:

Оказывается, что это пример неудачной инициализации VALUE sсоздан в C.

Другими словами, обязательно сделайте *(VALUE*)a = INT2FIX(0), прежде чем пытаться получить доступ к a.

Я все еще думаю, что вопрос актуален.Мне не удалось найти действительно хороших примеров маркировки для уборки мусора, в StackOverflow или где-либо еще.Если вы можете предоставить такой пример и / или объяснение, я отмечу это как правильный ответ на этот вопрос.

1 Ответ

1 голос
/ 14 августа 2012

Ruby's Mark-and-Sweep GC работает в два этапа.

Первый этап отмечает живые объекты. Он работает рекурсивно, вызывая функцию маркировки каждого известного «живого объекта». Начальный набор живых объектов создается путем сканирования стека C каждого известного потока Ruby или каждого зарегистрированного глобального объекта (есть функция C для регистрации / отмены регистрации «известных живых» объектов). Функция маркировки объекта X должна затем вызывать rb_gc_mark для каждого объекта, на который ссылается X. Другими словами, то, что вы делаете, это именно то, что вы должны делать.

Однако, как вы заметили позже, никакое возможное значение VALUE не является допустимым объектом Ruby. Тем не менее, я считаю, что инициализация с помощью Qnil (то есть nil) была бы более рубиновой.

...