[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: sizeof function closures in lua 5.1?
- From: Jim Pryor <lists+lua@...>
- Date: Mon, 7 Sep 2009 16:30:04 -0400
Thanks for your quick replies. And Peter, thanks for pointing me to
those declarations, this is exactly the info I was seeking but I don't
yet know my way around the Lua source.
Comments below...
On Mon, Sep 07, 2009 at 02:59:02PM +0100, Peter Cawley wrote:
> >From lobject.h, the definition of LClosure (the structure for Lua closures):
> typedef struct LClosure {
> GCObject *next;
> lu_byte tt;
> lu_byte marked;
> lu_byte isC;
> lu_byte nupvalues;
> GCObject *gclist;
> struct Table *env
> struct Proto *p;
> UpVal *upvals[1];
> } LClosure;
>
> >From the above, you can see that a Lua closure, in memory, takes 4
> pointers, plus 4 bytes, plus maybe some padding bytes between
> nupvalues and gclist (i.e. 4 padding bytes on x64 to align gclist on
> an 8 byte boundary), and then one extra pointer (UpVal*) for each
> upvalue which it references. If two or more closures share an upvalue,
> then just one UpVal structure will be allocated for that upvalue.
> Otherwise, an UpVal structure is allocated for each upvalue.
If a closure has multiple upvalues, then just one LClosure record is
created, with the upvals array having additional entries? Right?
> If upvalues are not shared, then for a closure with N upvalues, the
> required memory will probably be:
> sizeof(void*) * (5 + N) + N * (sizeof(void*) * 3 + 16)
> where sizeof(void*) == 4 on x86 and sizeof(void*) == 8 on x64.
This estimation exactly predicts the results I was seeing: 88 bytes for
any closure with 1 upvalue on a x64 machine. It matters not whether the
upvalue in question is ever "changed"---the report on the WoW wiki page
must be confused. I think what happened was they had an example where
the upvalues were local to a for block, so everytime the for block
executed they created a closure with a new upvalue. Whereas in the case
they were contrasting, they were creating multiple closures that shared
a single upvalue. In that case, there would be mutiple LClosure records,
but all pointing to a single UpVal record, correct?
I was still puzzled why my example...
function make_closure4(x)
local function static_closure(x) -- this is in make_closure1 style
return function(y)
return x+y
end
end
x = x==nil and 0 or x
return static_closure(x)
end
was being report as taking 128 bytes. Then in the process of writing up
this email I realized that my sizeof function was only doing a garbage
collect before executing make_closure4. We also need to do one _after_
executing, to get an accurate estimate of the size of make_closure4's
return value. Once I did that, I got 88 bytes here too.
So my puzzlement is all solved. Thanks for the help.
--
Jim Pryor
jim@jimpryor.net