Сборка "мусора" с Ruby C Расширение

Я прокладываю себе путь через Хорька (порт Ruby Lucene) код для решения ошибки. Код хорька является главным образом расширением C Ruby. Я сталкиваюсь с некоторыми проблемами со сборщиком "мусора". Мне удалось зафиксировать его, но я не полностью понимаю свою фиксацию =) Я надеюсь кто-то с более глубоким знанием Ruby и расширения C (это - мой 3-й день с Ruby), может уточнить.Спасибо.

Вот ситуация:

Некоторые, куда у Хорька C код, я возвращаю "Маркер" в землю Ruby. Код похож

static VALUE get_token (...)
{
  ...
  RToken *token = ALLOC(RToken);
  token->text = rb_str_new2("some text");
  return Data_Wrap_Struct(..., &frt_token_mark, &frt_token_free, token);
}

frt_token_mark называет rb_gc_mark (маркер-> текст), и frt_token_free просто освобождает маркер со свободным (маркер)

В Ruby этот код коррелирует к следующему:

маркер = @input.next

В основном @input установлен на некоторый объект, называние следующего метода на нем инициировало get_token C вызов, который возвращает маркерный объект.

На земле Ruby я затем делаю что-то как w = token.text.scan ('\w + ')

Когда я выполняю этот код внутри некоторое время 1 цикл (для изоляции моей проблемы), в какой-то момент (примерно, когда мое рубиновое место мадам процесса переходит к 256 МБ, вероятно, некоторый порог GC), Ruby умирает с ошибками как

метод проверки обратился к завершенному объекту

Или просто дампы ядра. Мое предположение было то, что token.text был собран "мусор".

Я не знаю достаточно о Ruby C расширение для знания то, что происходит с возвращенными объектами Data_Wrap_Struct. Кажется мне, присвоение на земле Ruby, маркер =, должно создать ссылку на него.

Мое "обходное решение" / "фиксация" должна создать переменную экземпляра Ruby в объекте, упомянутом @input, и хранит маркерный текст там, для получения дополнительной ссылки на него. Таким образом, код C похож

RToken *token = ALLOC(RToken);
token->text = rb_str_new2(tk->text);
/* added code: prevent garbage collection */
rb_ivar_set(input, id_curtoken, token->text);
return Data_Wrap_Struct(cToken, &frt_token_mark, &frt_token_free, token);

Таким образом, теперь я создал "curtoken" во входной переменной экземпляра и сохранил копию текста там... Я заботился для удаления/удаления этой ссылки в бесплатном обратном вызове класса для @input.

С этим кодом это работает в этом, я больше не получаю завершенную объектную ошибку.

Фиксация, кажется, имеет смысл мне - это сохраняет дополнительное касательно в curtoken к строке token.text, таким образом, экземпляр token.text не будет удален до следующего раза @input.next называют (в котором времени другой token.text заменяет старое значение в curtoken).

Мой вопрос: почему это не работало прежде? Не был должен Data_Wrap_Structure возвращать объект, который при присвоении на земле Ruby имеет действительную ссылку и не быть удаленным Ruby?

Спасибо.

5
задан Jon Seigel 22 July 2010 в 21:53
поделиться

1 ответ

При вызове сборщика мусора Ruby, он имеет фазу отметки и фазу зачистки. Фаза разметки отмечает все объекты в системе путем разметки:

  1. всех объектов, на которые ссылается рамка рубинового стека (например, локальные переменные)
  2. всех глобально доступных объектов (например, на которые ссылается константа или глобальная переменная) и их дочерних/отчуждающих, и
  3. всех объектов, на которые ссылается ссылка в стеке, а также их дочерних/отчуждающих.

а также ряда других объектов, которые не имеют значения для этого обсуждения. Затем на этапе развертки уничтожаются все недоступные объекты (т.е. те, которые не были помечены).

Data_Wrap_Struct возвращает ссылку на объект. Пока эта ссылка доступна в рубиновом коде (например, хранится в локальной переменной) или находится на стеке (на него ссылается локальная переменная C), объект не должен подвергаться подметанию.

Это выглядит так, как будто из того, что вы разместили, токен->текст собирает мусор. Но почему он собирается? Он не должен быть помечен. А сам объект Жетона помечен? Если да, то текст с токеном должен быть помечен. Попробуйте установить точку останова или распечатать сообщение в функции маркеровки, чтобы увидеть.

Если маркер не будет помечен, то следующий шаг - выяснить, почему. Если маркер помечен, то следующий шаг - выяснить, почему подметается строка, возвращаемая методом text() (возможно, это не тот же самый объект, который помечается).

Также, Вы уверены, что именно текстовый член маркера вызывает исключение? Глядя на:

http://github.com/dbalmain/ferret/blob/master/ruby/ext/r_analysis.c

я вижу, что и маркер, и поток маркеров имеют text() методы. Структура TokenStream не содержит ссылки на свой текстовый объект (не может, т.к. это C-структура без знания рубина). Таким образом, объект Ruby, обёртывающий структуру C, должен содержать ссылку (и это делается с помощью rb_ivar_set).

Структура RToken не должна этого делать, так как она помечает свой текстовый член в своей маркерной функции.

Еще одна вещь: вы можете иметь возможность воспроизвести эту ошибку, явно вызывая GC.start в своем цикле, вместо того, чтобы выделять так много объектов, что мусорный коллектор сработает. Это не исправит проблему, но может упростить диагностику.

3
ответ дан 15 December 2019 в 06:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: