HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Memory Pool and Block Alignment

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
blockalignmentmemoryandpool

Problem

I have written a memory pool (pool_allocator) that was described in a book I am reading (Game Engine Architecture). The interface is pretty basic:

  • The constructor: pool_allocator(std::size_t count, std::size_t block_size, std::size_t alignment);.



  • void* allocate();, which returns a pointer to a memory location with (at least) the requested alignment.



  • void free(void* block); which returns the block to the pool.



The general design is not complex, either. The constructor uses operator new() to allocate a chunk of memory, and that memory is treated as a linked list - any calls to allocate and free operate on the head of the list.

However, this is the first time I have ever given alignment any real consideration, and apparently if I use enough {static,reinterpret}_casts, I start to question that the Earth is round. I would be grateful for comments. My main concerns are:

  • Is alignment handled properly? I think align_head() is okay, but what about minimum_alignment() and padding()?



  • Are the reinterpret_cast and static_cast calls used properly, or are there better alternatives? I understand that they are necessary when handling raw data, but I am out of my comfort zone here.



If you want to go the extra mile and point out other deficiencies (which is more than welcome), keep in mind that in the current design it is not the responsibility of this object to handle error conditions or construct objects, just manage a chunk of memory.

```
class pool_allocator {

public:

typedef void* pointer_type;

public:

pool_allocator(std::size_t count, std::size_t block_size, std::size_t alignment)
: m_data(nullptr)
, m_head(nullptr)
, m_blocks(count)
, m_block_size(block_size)
, m_padding(0)
{
// each block must be big enough to hold a pointer to the next
// so that the linked list works
if (m_block_size (result));
return result;
}
}

// r

Solution

I think you have some fundamental misunderstandings about alignment (and you can simplify your code a lot):

3.11 Alignment


3: Alignments are represented as values of the type std::size_t. Valid alignments include only those values returned by an alignof expression for the fundamental types plus an additional implementation-defined set of values, which may be empty. Every alignment value shall be a non-negative integral power of two.

So you can the alignment requirements of a type from alignof(). This value is a power of 2.


5: Alignments have an order from weaker to stronger or stricter alignments. Stricter alignments have larger alignment values. An address that satisfies an alignment requirement also satisfies any weaker valid alignment requirement.

If something satisfies the alignments for a larger alignment. Then it automatically satisfies alignment requirements for smaller values.

Thus if memory is aligned for an object of size N. Then it is also correctly aligned for objects that are smaller than 'N'.

18.6.1.1 Single-object forms [new.delete.single]


void* operator new(std::size_t size);

1: Effects: The allocation function (3.7.4.1) called by a new-expression (5.3.4) to allocate size bytes of storage suitably aligned to represent any object of that size.

Thus using new to allocate memory for a space of size 'M' means the memory returned will also be aligned for objects of size 'M'. This also means that it aligned for all objects that are smaller than 'M'. Thus for your block of memory that will hold multiple objects of type 'N' such that `M = Count*alignof(N)' it is automatically aligned for all objects of type 'N'.

Context

StackExchange Code Review Q#31779, answer score: 3

Revisions (0)

No revisions yet.