在自定义双端基于堆栈的分配器中对齐内存如何工作?

时间:2018-11-20 04:16:49

标签: c++ memory-management

我正在读一本有关制作游戏引擎的书,因为我想创建自己的书,在书中它建议编写自己的自定义分配器,所以我从书中所描述的出发,并制作了一个基于堆栈的双端分配器。该书还提到,所有分配器都应能够分配对齐的内存。我在理解这本书为何实施对齐方式方面遇到了一些麻烦。本书中有一个函数,它接受您要分配的数量的大小以及对齐的大小。它说对齐方式应该永远只有2的幂,这是我开始无法获得的,并且还确保它不能大于128。我的问题是为什么?我有一个叫做Sprite的类,sizeof(Sprite)=136。假设我想用一个Sprite和一个int构造一个结构。对齐方式是什么,因为sizeof(Sprite)为136,sizeof(int)为4。在这种情况下,应该对齐什么?如何使用这种方法?

编辑:  我读了“内存对齐的目的”,那里的答案根本没有帮助我。我了解内存对齐的目的以及32位内存应如何对齐4字节。我也知道4字节对齐的内存驻留在4倍整数(即0x0、0x4、0x8或0xC)的半字节地址上。我只是不明白当我拥有136字节的内存(与我的Sprite类的情况一样)并且与4字节的int具有相同的结构时会发生什么。我还想知道为什么该方法要求对齐方式为2的幂且小于128。

以下是对齐代码:

// Allocate memory in an efficient way which means aligning it
// IMPORTANT: the alignment must be a power of 2 (usually 4 or 16)
void* DESA::allocAligned(size_t size_bytes, size_t alignment, unsigned int flag) {
    assert(flag == LEFT | flag == RIGHT);

    assert(alignment >= 1);
    assert(alignment <= 128);
    assert((alignment & (alignment - 1)) == 0); // Make sure it's a power of 2

    // Total amount of bytes
    size_t expandedSize_bytes = size_bytes + alignment;

    // Allocate unaligned memory and convert to uintptr_t
    // allocUnaligned just increments a pointer
    std::uintptr_t rawAddress;
    if (flag == LEFT)
        rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, LEFT));
    else if (flag == RIGHT)
        rawAddress = reinterpret_cast<std::uintptr_t>(allocUnaligned(expandedSize_bytes, RIGHT));

    // Calculate misalignment
    size_t mask = alignment - 1;
    std::uintptr_t misalignment = rawAddress & mask;
    std::ptrdiff_t adjustment = alignment - misalignment;

    // Calculate the adjusted address
    std::uintptr_t alignedAddress = rawAddress + adjustment;

    // Store the adjustment in the byte immediately preceding the adjusted address
    assert(adjustment < 256);
    U8* pAlignedMem = reinterpret_cast<U8*>(alignedAddress);
    pAlignedMem[-1] = static_cast<U8>(adjustment);

    return static_cast<void*>(pAlignedMem);
}

0 个答案:

没有答案