lua-users home
lua-l archive

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


> > The nature of Lua's growing of its internal arrays lends itself to 
> > fragmentation levels that aren't acceptable in a tight memory 
> > environment (such as a game console or embedded device).
> 
> In my project I gave up on using Lua in the "main loop" long 
> ago and just confined it to init time.  Even so it's much 
> better than life-before-Lua.

Agreed, although I've gotten away with making Lua run pretty effectively
in the main loop, with some tuning.

> Still, I'm interested in seeing how others manage in embedded 
> and hard real-time apps.  Have you considered keeping a 
> separate heap for use by Lua? This would localize the 
> fragmentation and reduce its effect assuming Lua is not 
> allocating large blocks of memory such as for sound or 
> animation data. It's the mixing of the large and small blocks 
> that makes fragmentation an issue.

My project has a specialized memory manager that supports heaps (and
heaps within heaps), but also supports bottom of heap and top of heap
allocations.

Consider the optimization I just made to Lua.  With any calls to the
callback for realloc() (see my earlier email on replacing the internal
memory allocator with callbacks instead of defines), an allocation type
is passed with.  Currently, this type can be LUA_ALLOC_NORMAL or
LUA_ALLOC_TEMP.  LUA_ALLOC_TEMP acts as a hint to the memory allocator.
In my case, I use the LUA_ALLOC_TEMP hint to allocate off the top of the
heap.

I use the the LUA_ALLOC_TEMP behavior in two places in Lua.  The first
is luaO_openspaceaux().  For all intents and purposes, the buffer
generated by this function is temporary.  I allocate it at the top of
the heap, so when it is freed, it doesn't fragment the bottom of the
heap, which is where most allocations occur.

The second place is even more important.  It is implemented in
lundump.c.  It causes the main function of a chunk to be allocated at
the top of the heap.  This includes the code, line information, proto,
closure, and one or two other items.  Since most of my script executions
are through lua_dofile() (instead of lua_loadfile()), the garbage
collection picks up the one time execution of the main function (which
can account for hundreds of kilobytes) and removes it from memory.  No
fragmentation of the lower part of the heap occurs.

The section I'll be investigating next is the string allocator.  By
allocating varied sizes of strings, when the garbage collector kicks in,
hard to fit holes are left behind.  I am investigating allocating string
buffers of specific sizes, say, increments of 16 bytes, to make fitting
newly allocated memory more robust.  I am unsure whether this will have
any good effect or not.  I'll keep everyone apprised.

The following functions have allowed me to remove most undesirable
fragmentation:

LUA_API void lua_setminimumstringtablesize(int numstrings);
LUA_API void lua_setdefaulttagtablesize(int numtags);
LUA_API void lua_setminimumglobaltablesize(int numentries);
LUA_API unsigned int lua_setmainfunctionallocflags(lua_State *L,
unsigned int allocFlags);
LUA_API void lua_setminimumauxspace(int size);

I intend to post full definitions for them, and the related changes to
the Lua code soon.

Again, it's not perfect.  It is, however, a great deal better than it
was before.

Thanks,
Josh