I am using cocos2d-x with Lua for development. Recently I used Instruments and have discovered some amount of memory which is abandoned:
cocos2d-x performs release on objects in its own autorelease pool, but I still have reference coming from Lua.
How to figure out when those references are made?
I need to free that memory to avoid abandoned memory allocations left in space. The only thing that comes to my mind is to use some Lua debugger to look after not nil Lua pointers.
If I only knew which Lua reference holds the pointer, I could release it manually then.
Your question was a bit oddly worded. But as I understand it, your Lua script has references to objects allocated in external code. And as long as Lua has these references, the external code won’t free those resources. And you believe that those resources should be freed.
The first thing you should check is that your Lua interface code uses metamethods to properly clean up references. That is, when Lua is finished with an object reference, there’s a metamethod attached (
__gc) that will inform the external code that Lua is finished with the object.For the rest of this post, I will assume that this code exists and functions properly. You should verify this yourself.
Given that assumption, what you’re seeing happens for one of two reasons:
Your Lua code has finished using all of its references, but hasn’t cleaned them up yet. By this, I mean that Lua scripts no longer have the references in any local variables, global variables, etc. In this case, what’s happened is that Lua’s garbage collector simply hasn’t run and cleaned up stuff yet. So you’ll need to do that with
lua_gc(L, LUA_GCCOLLECT, 0);. If this is the case, then after running this function all references from Lua should have been cleaned up.Your Lua code still has active references to external objects lurking about.
Dealing with case #2 is difficult. It is the responsibility of Lua code to be… responsible. It should store references when it needs to refer to stuff, and then forget about those references afterwards. By that, I mean don’t store the value in a non-local variable (and by “non-local”, I also mean to avoid locals that are used by nested function definitions).
There is no means to find where those references still exist; after all, Lua values do not necessarily have a name. Also, Lua doesn’t really give you a way to iterate through every possible variable in the
lua_State. Even if there was, there is certainly no means of simply blanking those references out. After all, Lua code can still touch them. If you blanked them, Lua code would crash when it tried to talk to those objects. So even if you could do what you wanted, it would be counter-productive.I would suggest one of three methods for dealing with this:
Exercise discipline in your scripting. Make sure you know where all of your non-Lua objects are stored. Make sure that these objects are released when they should be. Know where you put these external objects, and make sure that they are released on time. By “released,” I mean simply overwriting their value with
nil.Build a layer of insulation between your script and your source code. Rather than directly giving Lua pointers to Cocos2D-X objects, give it pointers to a special object that may contain a reference to a Cocos2D-X object. That way, you can control when these objects get released directly by telling this control object to drop its reference. If Lua calls an empty control object, the function will return… something innocuous (so that you don’t crash). Obviously, Lua should have a function to see if it is a valid control object.
Do whatever you want in Lua, but then destroy the entire Lua state when it’s time to free resources. Your current method is very fine-grained. Lua creates some resources, and Lua then decides when they go away. A more strict resource management scheme would be for Lua scripts to load some resources and reference resources. But then when it’s time to destroy all of those resources, you just
lua_closethelua_Stateitself. That will release all references, thus releasing those resources. Problem solved.