lua-users home
lua-l archive

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

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
    x = x==nil and 0 or x
    return static_closure(x)

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