views:

479

answers:

2

I've read somewhere on here where someone recommended using Loki's Small Object Allocator for Lua to help improve allocation performance. I read through the section in 'Modern C++ Design' and I think I've got a good enough understand on using Loki for this, with the exception of not using the SmallObject - Lua just wants raw memory, so I took a first stab at using the SmallObjAllocator directly.

The allocations seem like they are working, but everything completely fails once I tried to load a script (either using lua_load() with my own custom reader, or using luaL_loadfile() to read the file directly).

Here's my implementation of the SmallObjAllocator class:

class MySmallAllocator : public Loki::SmallObjAllocator { public: MySmallAllocator( std::size_t pageSize, std::size_t maxObjectSize, std::size_t objectAlignSize ) : Loki::SmallObjAllocator( pageSize, maxObjectSize, objectAlignSize ) { }

virtual ~MySmallAllocator() { } }; static MySmallAllocator alloc_(4096,64,4);

And when I create the Lua state, I give it the allocation function that uses this new allocator:

masterState_ = lua_newstate(customAlloc_, &heap_);

void* customAlloc_( void* ud, void* ptr, size_t osize, size_t nsize ) { // If the new size is zero, we're destroying a block if (nsize == 0) { alloc_.Deallocate( ptr ); ptr = NULL; } // If the original size is zero, then we're creating one else if (0 != nsize && 0 == osize) { ptr = alloc_.Allocate( nsize, false ); } else { alloc_.Deallocate( ptr ); ptr = alloc_.Allocate( nsize, false ); }

return ptr; }

And here I go to load the file:

int result = luaL_loadfile( masterState_, "Global.lua" );

If i have a simple for loop in Global.lua the system never returns from the call to luaL_loaloadfile():

for i=1,100 do
 local test = { }
end

What is wrong, how should I diagnose this, and how do I fix it?

+3  A: 

The issue that leaps out at me is that your custom allocator needs to behave like C's realloc() function. This is critical in the case where osize != nsize and both are non-zero. The key property of realloc() in this case is that it preserves the values of the first min(osize,nsize) bytes of the old block as the beginning of the new block.

You have:

    else
    {
            alloc_.Deallocate( ptr );
            ptr = alloc_.Allocate( nsize, false );
    }

which abandons all the content of the old allocation.

This is specified

The allocator function must provide a functionality similar to realloc, but not exactly the same.

in the documentation for lua_Alloc.

RBerteig
A: 

Good call! I really didn't understand what realloc() did, so you set me on the right track. I replaced the reallocation part to the code below and everything works now, but my performance right now is actually a bit worse than just using the HeapAlloc/HeapReAlloc/HeapFree I had before.

    void* replacementPtr = alloc_.Allocate( nsize, true );
    memcpy( replacementPtr, ptr, min(osize, nsize) );
    alloc_.Deallocate( ptr );
    ptr = replacementPtr;

I suspect an issue is because Loki uses malloc/free for each Chunk as well as when the size is > GetMaxObjectSize()...