[osg-users] [osgPlugins] Lua: deterministic destruction of the script engine / leaks caused by circular references

Hannes Pabst johannes.pabst at ocilion.com
Thu Sep 19 05:35:56 PDT 2019

Consider the following Lua script:


function makeObjectWithCallback()
   local object = new "osg::Object"
   function object:process()
         print "Hello"

   return object

The function makeObjectWithCallback will create an osg::Object which has a LuaCallbackObject named "process", stored within its user data.
The LuaCallbackObject itself stores an ref_ptr to the LuaScriptEngine for being able to call the function defined within Lua.
Unfortunately the references now are circular: 

LuaScriptEngine -> Lua -> Object -> LuaCallbackObject -> LuaScriptEngine

Once the script is executed it is hard to get rid of the LuaScriptEngine object.
Simply deleting all references to the ScriptEngine and the returned Object on the cpp side will cause a leak, as the Lua state keeps them alive.
Even if the variable "object" above is only temporarily used in Lua, a GC run is necessary to break the Lua -> Object dependency.
But who shall trigger that, if all references on the cpp side are gone and Lua cannot be called anymore?

Here is the code to run the Lua script above, that will produce the leak:


void runScript()
   osg::ref_ptr<osg::ScriptEngine> luaScriptEngine = osgDB::readFile<osg::ScriptEngine>("ScriptEngine.lua");
   osg::ref_ptr<osg::Script> script = osgDB::readScriptFile("script.lua");
   osg::Parameters inputParameters;
   osg::Parameters outputParameters;
   luaScriptEngine->run(script.get(), "makeObjectWithCallback", inputParameters, outputParameters);

My intention is to use LuaCallbackObjects but also to have the possibility to clean up and reload the Lua script at any time by re-instantiating the LuaScriptEngine. 
Unfortunately there seems to be no general and easy way to destroy the shared LuaScriptEngine object. 

Wouldn't it be a more practical design to have the LuaCallbackObject only weakly reference the LuaScriptEngine?
If the ScriptEngine object is gone, callbacks into Lua could simply do nothing – per definition.
I understand such change would break existing code, in situations where one creates a LuaScriptEngine object on the fly running a script that hooks to the OSG runtime system.
As far as I understand the Lua plugin code, the lua_close call in the destructor of LuaScriptEngine releases all references held by Lua and thus would be able break up all other eventually existing circular references - so the class would in principle be ready to act as a “master object” on the cpp side, that is able to control the lifetime of the whole Lua system.

I have made this change to the Lua plugin code (simply by replacing the ref_ptr by an observer_ptr) and for my purposes it seems to work well, but wonder if this is an issue that should generally be addressed within OSG.

Read this topic online here:

More information about the osg-users mailing list