|
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
>>