5

我必须实现 malloc/realloc/free 的优化版本(为我的特定应用程序量身定制)。目前代码在特定平台上运行,但如果可能的话,我想以可移植的方式编写它(平台将来可能会改变),或者至少我想将可能的平台差异集中在一个单一的点(可能是 .h)。我知道一些问题:

  • 内存对齐的差异
  • 适合“通用”分配的最小内存块大小的差异
  • 指针大小的差异

(这里我将忽略用于内存分配的基本系统服务的差异,因为在某些嵌入式系统上它们可能根本不可用。假设我们在一个大的预分配内存块上工作以用作“堆”)。

问题:

  • C 中是否有用于这种目的的标准宏或函数?
  • 在这份工作中我还可能面临哪些其他问题?
4

6 回答 6

3

确保您保持适合所有基本类型的对齐方式的经典方法是定义一个联合:

union alloc_align {
    void *dummy1;
    long long dummy2;
    long double dummy3;
};

...然后确保您分发的地址始终偏移sizeof (union alloc_align)您从系统内存分配器收到的对齐地址的倍数。

我相信在 K&R 中描述了与此类似的方法。

于 2012-01-23T09:35:14.297 回答
1

不幸的是,对齐的内存因编译器而异(这是一个问题),在 MSVC 上,你aligned_malloc有 POSIX memalignfor Linux,然后还有_mm_alloc 在 ICC、MSVC 和 GCC、IIRC 下工作的,应该是最便携的.

第二个问题是对齐造成的内存浪费,这不是主要问题,但在嵌入式系统上,这是需要注意的。

如果您正在堆栈分配需要对齐的东西(例如 SIMD 类型),您还需要查看__attribute__((__aligned__(x)))and __declspec(align(x))

就指针算术的可移植性而言,您可以使用来自stdint.h/的类型pstdint.h来执行此操作,但标准可能会在uintptr_t与指针之间进行转换时说明 UB(不幸的是,标准不是我的强项:()。

于 2012-01-23T09:19:41.330 回答
1

对齐功能仅在新的 C 标准 C11 中处理。它有关键字_Alignof_Alignas功能aligned_alloc。使用大多数现代编译器来模拟这些功能并不难(如其他答案所示),因此我建议您自己编写小宏或包装器,您将根据__STDC_VERSION__.

于 2012-01-23T09:27:12.353 回答
1

主要问题是您只向malloc()和朋友提供内存块的总大小,而没有任何有关对象粒度的信息。如果您将分配视为对象数组,那么您的大小是基本对象的 sizeof,而数字 n 是数组中的对象数,例如:

p = malloc(sizeof(*p) * n);

如果你只有总大小,那么你不知道是 s=4 和 n=10,还是 s=2 和 n=20,或者 s=1 和 n=40,因为所有乘以总大小40 字节。

所以基本问题是,您是否想要直接替代原始函数,例如,当您在整个代码库中抛出本地调用时,或者您是否具有带有包装函数的集中式和 DRY 模块化。在那里你可以使用提供 s 和 n 的函数。

void *my_malloc (size_t s, size_t n)

大多数时候,当返回的绝对内存地址是 s 的倍数以保证正确对齐时,应该是一个安全的选择。

或者,在移植您的实现时,您只需查看本机malloc()用于目标平台的对齐方式(例如 16 的倍数),并将其用于您自己的实现。

于 2012-01-23T09:33:25.197 回答
0

如果您查看#pragma pack,这可能会对您有所帮助,因为它允许您定义结构打包并在大多数编译器上实现。

于 2012-01-23T09:00:45.087 回答
0

C 表示malloc返回一个指向任何目的的内存对齐的指针。C 中没有可移植的方式来使用 C 功能实现这一点。这样做的结果malloc是,如果用 C 语言编写,就不能以可移植的方式编写函数。

(C99, 7.20.3p1) “如果分配成功,则返回的指针经过适当对齐,以便可以将其分配给指向任何类型对象的指针,然后用于访问分配的空间中的此类对象或此类对象的数组(直到空间被显式释放)。”

于 2012-01-23T09:35:50.827 回答