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