Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using allocators to replace malloc()/free()?

Tags:

c++

memory

malloc

Is there any portable way to replace usage of malloc()/free() with wrappers around STL-like allocators?

The context: I have a C library that allows to specify custom malloc()/free()-like functions for memory management, and which is used in multi-threaded contexts. Looking around for a good multi-threaded allocator, I've found that GCC-libstdc++'s mt_alloc performs very well for my workloads. Now I would like to use it in said C library, but how to do it?

The major problem I see is in the deallocate() function, which, contrary to free(), takes the size of the allocated memory block in addition to its address. So I need somehow to keep track of the size associated to every memory allocation, so that it can be fed back to deallocate() when freeing the memory. The simplest solution I've thought about to solve this is to store the size of the allocated memory at the beginning of the memory block, but then I'm not sure how to solve alignment issues that could arise.

Is there any simple solution that I'm overlooking?

like image 342
bluescarni Avatar asked Mar 03 '26 14:03

bluescarni


2 Answers

On my platform, malloc ensures that allocated memory is aligned at an 8-byte boundary. To mimic this behavior, use an allocator<uint64_t>:

#include <stdint.h>
#include <ext/mt_allocator.h>

static __gnu_cxx::__mt_alloc<uint64_t> theAllocator;

void* mtmalloc(size_t size)
{
    // Divide size by sizeof(uint64_t) and round up
    size_t payloadElementCount = (size + sizeof(uint64_t) - 1) /
                                 sizeof(uint64_t);

    // Add an extra uint64_t to store the chunk size
    size_t chunkElementCount = 1 + payloadElementCount;

    // Allocate the chunk
    uint64_t* chunk = theAllocator.allocate(chunkElementCount);

    // Store the chunk size in the first word
    chunk[0] = chunkElementCount;

    // Return a pointer past where the chunk size is stored
    return static_cast<void*>(chunk + 1);
}

void mtfree(void* pointer)
{
    // The chunk begins one word before the passed in pointer
    uint64_t* chunk = static_cast<uint64_t*>(pointer) - 1;

    // Retrieve the chunk size
    size_t chunkElementCount = chunk[0];

    // Deallocate the chunk
    theAllocator.deallocate(chunk, chunkElementCount);
}

int main()
{
    int* array = (int*)mtmalloc(sizeof(int) * 4);
    array[0] = 0;
    array[1] = 1;
    array[2] = 2;
    array[3] = 3;
    mtfree(array);
}

For your platform, substitute uint64_t with the appropriate type.

You should test this with something like Valgrind to insure there are no memory leaks!


Instead of uint64_t, you can use GCC's __BIGGEST_ALIGNMENT__ and Boost's aligned_storage type trait for a solution portable to GCC compilers:

typedef boost::aligned_storage<__BIGGEST_ALIGNMENT__, __BIGGEST_ALIGNMENT__> AlignedType;

like image 166
Emile Cormier Avatar answered Mar 06 '26 11:03

Emile Cormier


There's a great series about this written on altdevblogaday by Paul Laska. Here's the link to the first article: http://altdevblogaday.org/2011/04/11/ready-set-allocate-part-1/

In the article he takes care about block-size allocations and alignment issues. It should provide a well-thought and well-written solution for taking care of your deallocate-issues.

like image 37
Simon Avatar answered Mar 06 '26 11:03

Simon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!