lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> Yes. You can resurrect a Lua value from within its `__gc()` metamethod
by making it reachable again. This will defer memory deallocation until
the object becomes unreachable. The `__gc` metamethod will not run a
second time for a resurrected object (in Lua 5.3 it will if you call
`setmetatable()` again when you resurrect the object). So contrary to
what I've said before, removing the metatable is unnecessary even in Lua
5.3.

Then that completely solves my problem, thanks!

On Fri, Nov 20, 2015 at 8:22 AM Philipp Janda <siffiejoe@gmx.net> wrote:
Am 20.11.2015 um 10:57 schröbte Thiago Padilha:
>> In your `A.__gc()` metamethod add the A userdata to a global table and
> remove its metatable (to prevent `__gc()` from being called again in Lua
> 5.3). Then remove the A userdata from that table when C is called.
>
> That seems like something that might work. Let's see if I understood
> correctly: If I create a reference to "A" (in the registry, for example)
> while its __gc method is being called, I'm effectively stopping lua from
> finishing the garbage collection process right? Is this how Lua 5.1 and
> later works?

Yes. You can resurrect a Lua value from within its `__gc()` metamethod
by making it reachable again. This will defer memory deallocation until
the object becomes unreachable. The `__gc` metamethod will not run a
second time for a resurrected object (in Lua 5.3 it will if you call
`setmetatable()` again when you resurrect the object). So contrary to
what I've said before, removing the metatable is unnecessary even in Lua
5.3.
But remember that during `lua_close()` everything becomes unreachable
including all values in the registry, so this trick won't work in that case.

You can find the details here[1].

   [1]:  http://www.lua.org/manual/5.3/manual.html#2.5.1


>
> On Thu, Nov 19, 2015 at 3:31 PM Philipp Janda <siffiejoe@gmx.net> wrote:
>
>> Am 19.11.2015 um 15:28 schröbte Thiago Padilha:
>>> Consider the following scenario:
>>>
>>> I have a userdata "A" being referenced referenced by another userdata
>> "B".
>>> "A" has the __gc metamethod that can be used to schedule its removal from
>>> "B", but note that the reference is not removed immediately, it is
>> deferred
>>> until a certain function "C" is called(This is how the library I'm
>> working
>>> with behaves). The problem is that if Lua frees "A" memory before "C" is
>>> called, "B" will be left with a dangling pointer that can cause memory
>>> errors when "C" is called later(It will be called for sure).
>>>
>>> What I want to achieve is to defer "A" memory from being freed until C is
>>> called. Is there a way to do this? I know that one option is to work with
>>> userdata that simply references "A" and take care of freeing memory
>> myself,
>>> but I'd rather avoid this because it would need a lot of refactoring in
>> the
>>> project I'm working on.
>>>
>>
>> This is probably your best option if the C call could happen after
>> `lua_close()` because all memory allocated by Lua is released at that
>> point.
>>
>> If you can rule that situation out:
>> In your `A.__gc()` metamethod add the A userdata to a global table and
>> remove its metatable (to prevent `__gc()` from being called again in Lua
>> 5.3). Then remove the A userdata from that table when C is called.
>>
>> HTH,
>> Philipp
>>