[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: dawn of the dead: dead coroutine as a key in a __mode="v" table
- From: Karel Tuma <ktuma@...>
- Date: Fri, 17 Nov 2006 00:31:45 +0100
sorry, gpm messed up the very important line with coroutine.resume() ;-)
try this:
weak = {}
setmetatable(weak, {__mode = "v"})
a = {}
b = coroutine.create(function(x) error() end)
coroutine.resume(b, a)
-- b still has "strong" reference to a
weak[b] = a
-- now there are no references to 'a' except the dead coroutine
a = nil
b = nil
-- the table has value of 'a' although noone is referring to it
collectgarbage("collect")
print(next(weak))
-- kill the value on dead's coroutine stack
a = next(weak)
print(coroutine.status(a))
debug.setlocal(a, 1, 1, "die hard")
collectgarbage("collect")
-- now the table is empty
print(next(weak))
On Thu, Nov 16, 2006 at 11:31:08PM +0100, Jerome Vuarand wrote:
> I don't understand your problem there. When I run your test, the first
> print displays nil, and coroutine.status throw an error because a is not
> a coroutine. That's the expected behaviour of that code.
>
> Is there a bug on your platform, or did you expect a different behaviour
> ?
>
> Karel Tuma wrote:
> > hello list,
> >
> > recently i've spent few hours finding out "mysterious memory leaks"
> > in one erlang-like system written in lua.
> >
> > some of you have probably been bitten by what i call "lua's weak
> > paradox", that is
> >
> > http://lua-users.org/wiki/GarbageCollectingWeakTable
> >
> > basically it means that weak element (either key or value) of
> > a table wont
> > get garbage collected if there exists _any_ reachable strong
> > path to that
> > value, including the strong part of the table row in question.
> > somehow, it's so wicked it actually sounds right.
> > naturally, from my experience i thought this applies only to
> > tables with
> > either cyclic weak key or value, but still i got bitten by
> > this "feature"
> > today:
> >
> > weak = {}
> > setmetatable(weak, {__mode = "v"})
> >
> > a = {}
> > b = coroutine.create(function(x) error() end)
> >
> > -- b still has "strong" reference to a
> > weak[b] = a
> >
> > -- now there are no references to 'a' except the dead coroutine
> > a = nil
> > b = nil
> >
> > -- the table has value of 'a' although noone is referring to it
> > collectgarbage("collect")
> > print(next(weak))
> >
> > -- kill the value on dead's coroutine stack
> > a = next(weak)
> > print(coroutine.status(a))
> > debug.setlocal(a, 1, 1, "die hard")
> > collectgarbage("collect")
> >
> > -- now the table is empty
> > print(next(weak))
> >
> > as you can see, there is something wrong with this. the "dead"
> > coroutine makes "strong" reference to 'a' but there is no way
> > to kill that reference in the first place. i'd understand this
> > if it would be open upvalue, or the coroutine alive, but come on,
> > what's purpose of completely dead coroutine's stack making strong
> > references to my weak values?
> >
> > solution to this should be simple: ignore references from dead
> > coroutine's stack, i'm now trying to figure out how to hack this
> > into lua's gc (which is the most mysterious part of lua for me :)
> > the question is: will this break something? i know that coroutine's
> > upvalues should be left strong but i guess there will be also
> > something else because otherwise i dont see any rationale behind
> > this evil plot of coroutine walking zombies ;)
> >
> > //kt