Управление сборщиком мусора Lua5.1 - PullRequest
1 голос
/ 07 мая 2009

ОК, поэтому у меня есть класс C ++, который предоставляется Lua с помощью SWIG. Сценарий создает объект, но класс менеджера также имеет указатель на объект, поэтому его можно изменить в C ++ (или другом сценарии) по любой причине.

Проблема в том, что когда скрипт завершает работу, объект освобождается, как я могу контролировать то, что собирает сборщик мусора, без необходимости реализации метаметода gc?

Вот пример:

--Script that creates the object
someObject = Utils.Object("Obj name");

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

--Another script
obj = ObjManager:GetObject(0);

Ясно, что это не очень реалистичный пример, но, надеюсь, он иллюстрирует мой вопрос. Есть ли способ наложить вето на сборщик мусора без метаметода gc в C ++?

Просто чтобы уточнить, что менеджер находится в C ++, а Utils - это имя модуля, в котором находится открытый класс. Также объект регистрируется менеджером в своем конструкторе.

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 08 мая 2009

GC Lua знает только о ссылках, хранящихся в Lua, что является разумным ограничением реализации. Это подразумевает, что время жизни объекта находится под контролем Луа. Если объект, созданный посредством выполнения одного сценария или функции, должен быть доступен для более поздних сценариев или функций, ссылка на него должна быть сохранена в состоянии Lua, чтобы GC знал , и он все еще используется. В противном случае он неотличим от мусора и может быть удален в любое время.

Это одна из целей таблицы реестра Lua. Сторона C может легко содержать ссылку на любой объект Lua, поместив его в таблицу реестра. Ключом может быть какое-то уникальное значение, известное библиотеке C (адрес переменной static, преобразованной в легкие пользовательские данные, часто является хорошим выбором, поскольку он не может конфликтовать ни с одним ключом из любой другой библиотеки). В качестве альтернативы вызов функции luaL_ref(L, LUA_REGISTRYINDEX) поместит элемент на вершину стека в таблице реестра и вернет уникальный целочисленный ключ. Это хорошо работает для хранения предоставленной сценарием функции обратного вызова таким образом, чтобы она защищала функцию от GC и позволяла сохранять «указатель» (целочисленный ключ) на нее в структуре C, чтобы ее можно было извлечь и вызвать позже.

Обратите внимание, что luaL_ref() может использоваться для управления ссылками в любой таблице, поэтому вполне может иметь смысл использовать для этой цели таблицу, которая является частной для вашего модуля, а не таблицу глобального реестра. В этом случае сама таблица ObjManager может быть хорошим кандидатом.

0 голосов
/ 08 мая 2009

Да; У Utils.Object поместите объект в приватную таблицу. Тогда никогда не будет собрано, но вы можете играть в игры (код не проверен):

do
  local retained = { }  -- table forces objects to be retained
  local old_util_object = Util.Object
  Util.Object = function(...)
    local obj = old_util_object(...)
    retained[obj] = true
    return obj
  end
  Util.Free = function(obj)
    assert(retained[obj])
    retained[obj] = nil  -- now obj can be garbage-collected
  end
end

Если вы хотите решить ту же проблему на стороне C ++, пусть ваш код C ++ выделит личную таблицу и поместит ее в реестр Lua. Затем вы можете играть в ту же игру вставки / удаления, только используя C API вместо исходного кода Lua. Предполагая, что вы знакомы с Lua C API, все просто. Если вы раньше не использовали C API, никогда не будет лучшего времени для начала обучения.

...