Как маркировка должна выполняться на массивах VALUE* в расширении Ruby?
У меня есть тип матрицы, который содержит void*
массив, представляющий массив объектов (которые все являются одним типом в данной матрице, например, все целые числа C, все числа с плавающей запятой, двойные числа, различные структуры или, возможно, даже все Ruby VALUE
с).
Распределение памяти и сборка мусора, кажется, работает правильно, пока я не попытаюсь создать матрицу VALUE
s.
У меня определена следующая функция mark:
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.
Итак, мои вопросы:
Если это GC, то какой способ пометить массив
VALUE
s?Если это не GC, как мне диагностировать этот тип ошибки? Я никогда не видел ничего подобного.
РЕДАКТИРОВАТЬ:
Оказывается, это пример неудачной инициализации VALUE
s создан в C.
Другими словами, обязательно сделайте *(VALUE*)a = INT2FIX(0)
прежде чем пытаться получить доступ a
,
Я все еще думаю, что вопрос актуален. Мне не удалось найти действительно хороших примеров маркировки для уборки мусора, в Stackru или где-либо еще. Если вы можете предоставить такой пример и / или объяснение, я отмечу это как правильный ответ на этот вопрос.
1 ответ
Ruby's Mark-and-Sweep GC работает в два этапа.
Первый этап отмечает живые объекты. Он работает рекурсивно, вызывая функцию маркировки каждого известного "живого объекта". Начальный набор живых объектов создается путем сканирования стека C каждого известного потока Ruby или каждого зарегистрированного глобального объекта (есть функция C для регистрации / отмены регистрации "известных живых" объектов). Функция маркировки объекта X должна затем вызывать rb_gc_mark для каждого объекта, на который ссылается X. Другими словами, то, что вы делаете, это именно то, что вы должны делать.
Однако, как вы заметили позже, никакое возможное значение VALUE не является допустимым объектом Ruby. Тем не менее, я считаю, что инициализация с помощью Qnil (т.е. nil) была бы более рубиновой.