На самом деле, дополнительная глобальная переменная с устаревшей ссылкой на корабль будет достаточной, чтобы GC не отказался от объекта. Так что это можно обнаружить во время выполнения, заметив, что корабль сейчас «мертв» и отказавшись что-либо с ним делать. Это все еще не тот корабль, но, по крайней мере, вы не разбиваетесь.
Одна вещь, которую вы можете сделать, это хранить пользовательские скрипты в песочнице , возможно, в песочнице для каждого скрипта. Правильно манипулируя таблицей окружения песочницы или ее метатабельной таблицей, вы можете отказаться от всех или большинства глобальных переменных из песочницы до (или сразу после) вызова кода пользователя.
Очистка песочницы после звонков имеет преимущество в том, что отбрасывает дополнительные ссылки на вещи, которые не должны висеть вокруг. Это можно сделать, сохранив белый список полей, которым разрешено оставаться в среде, и удалив все остальные.
Например, следующее реализует изолированную программу для пользовательской функции со средой, содержащей только имена из белого списка за свежей скретч-таблицей, предоставляемой для каждого вызова.
-- table of globals that will available to user scripts
local user_G = {
print=_G.print,
math=_G.math,
-- ...
}
-- metatable for user sandbox
local env_mt = { __index=user_G }
-- call the function in a sandbox with an environment in which new global
-- variables can be created and modified but they will be discarded when the
-- user code completes.
function doUserCode(user_code, ...)
local env = setmetatable({}, env_mt) -- create a fresh user environment with RO globals
setfenv(user_code, env) -- hang it on the user code
local results = {pcall(user_code, ...)}
setfenv(user_code,{})
return unpack(results)
end
Это может быть расширено, чтобы сделать глобальную таблицу доступной только для чтения, отодвинув ее за еще один доступ с метатизацией, если хотите.
Обратите внимание, что полное решение для песочницы также учитывает, что делать с пользовательским кодом, который случайно (или злонамеренно) выполняет бесконечный (или просто очень длинный) цикл или другую операцию. Общие решения для этого - случайная тема обсуждения в Lua list , но хорошие решения трудны.