malloc 实现:检查分配对齐是否正确

问题描述 投票:0回答:1

我最新的测试失败了,但我想我已经找到了通过它的解决方案。它涉及使用alignof(max_align_t)(甚至alignof(long double)),但我不完全确定我对分配对齐的理解是否正确..

我的想法是,如果我的类型的实际大小不能被地址位置整除,我需要添加一些填充,直到满足条件。此过程通过创建可预测的模式帮助编译器更有效地访问内存!

如果我是对的,那么为什么最后一个测试没有通过?否则,请澄清!

void *malloc(size_t sz, const char *file, int line) {
  (void)file, (void)line; // avoid uninitialized variable warnings
  if (default_buffer.pos + sz > default_buffer.size) {
    // Not enough space left in default buffer for allocation
    gstats.nfail++;
    gstats.fail_size += sz;
    return nullptr;
  }
  // Here i'm checking for correct allocation alignement
  if (default_buffer.pos % sz != 0) {
    default_buffer.pos += default_buffer.pos % sz;
  }
  // Otherwise there is enough space; claim the next `sz` bytes
  void *ptr = &default_buffer.buffer[default_buffer.pos];

  default_buffer.pos += sz;
  gstats.ntotal++;
  gstats.total_size += sz;
  return ptr;
}

测试.cc

int main() {
double* ptr = (double*) malloc(sizeof(double));
assert((uintptr_t) ptr % alignof(double) == 0);
assert((uintptr_t) ptr % alignof(unsigned long long) == 0);
assert((uintptr_t) ptr % alignof(std::max_align_t) == 0);

    char* ptr2 = (char*) malloc(1);
    assert((uintptr_t) ptr2 % alignof(double) == 0);
    assert((uintptr_t) ptr2 % alignof(unsigned long long) == 0);
    assert((uintptr_t) ptr2 % alignof(std::max_align_t) == 0);
    
    free(ptr);
    free(ptr2);

}

我已经解决了该问题,并且我想了解为什么我的解决方案的替代方案无法在特定测试中发挥作用。所以基本上,我正在努力确保我的理解是正确的!

c memory malloc dmalloc
1个回答
0
投票

正如我在评论中提到的,您的对齐计算不正确。对齐值的典型方法是:

pos = (pos + align - 1) & ~(align - 1);

其中

align
是 2 的无符号幂。

由于您尝试在此处对齐缓冲区中的位置,因此必须小心,这实际上会导致内存中的相同对齐。这是一种可以对齐到任意地址的简单方法:

#include <stddef.h>
#include <stdint.h>

uintptr_t align_auto(uintptr_t ptr, size_t sz, size_t *palign)
{
    // Naive alignment calculation (you could do better)
    size_t align = 1;
    while (align < sizeof(max_align_t) && align < sz) align <<= 1;
    if (palign) *palign = align;

    // Align the pointer
    return (ptr + align - 1) & ~(align - 1);
}

在这里,您提供

ptr
,这是您要对齐的地址。然后计算分配
sz
所需的最小对齐方式。为了方便起见,它还输出所选的对齐方式。

查看实际效果:

void test(char* buffer, size_t sz)
{
    size_t alignment;
    uintptr_t base_ptr = (uintptr_t)buffer;
    uintptr_t aligned_ptr = align_auto(base_ptr, sz, &alignment);
    size_t offset = aligned_ptr - base_ptr;
    printf("-align=%p size=%zu alignment=%zu offset=%zu\n",
        aligned_ptr, sz, alignment, offset);
}

int main(void)
{
    char buffer[256];
    for (size_t offset = 0; offset < 16; offset++)
    {
        char* base = buffer + offset;
        printf("buffer=%p :\n", base);
        for (size_t sz = 1; sz < 16; sz += 3)
        {
            test(base, sz);
        }
        printf("\n", buffer);
    }
}

输出示例:

buffer=0x7ffd8bd97110 :
-align=0x7ffd8bd97110 size=1 alignment=1 offset=0
-align=0x7ffd8bd97110 size=4 alignment=4 offset=0
-align=0x7ffd8bd97110 size=7 alignment=8 offset=0
-align=0x7ffd8bd97110 size=10 alignment=16 offset=0
-align=0x7ffd8bd97110 size=13 alignment=16 offset=0

buffer=0x7ffd8bd97111 :
-align=0x7ffd8bd97111 size=1 alignment=1 offset=0
-align=0x7ffd8bd97114 size=4 alignment=4 offset=3
-align=0x7ffd8bd97118 size=7 alignment=8 offset=7
-align=0x7ffd8bd97120 size=10 alignment=16 offset=15
-align=0x7ffd8bd97120 size=13 alignment=16 offset=15

buffer=0x7ffd8bd97112 :
-align=0x7ffd8bd97112 size=1 alignment=1 offset=0
-align=0x7ffd8bd97114 size=4 alignment=4 offset=2
-align=0x7ffd8bd97118 size=7 alignment=8 offset=6
-align=0x7ffd8bd97120 size=10 alignment=16 offset=14
-align=0x7ffd8bd97120 size=13 alignment=16 offset=14

buffer=0x7ffd8bd97113 :
-align=0x7ffd8bd97113 size=1 alignment=1 offset=0
-align=0x7ffd8bd97114 size=4 alignment=4 offset=1
-align=0x7ffd8bd97118 size=7 alignment=8 offset=5
-align=0x7ffd8bd97120 size=10 alignment=16 offset=13
-align=0x7ffd8bd97120 size=13 alignment=16 offset=13

etc...
© www.soinside.com 2019 - 2024. All rights reserved.