什么是对齐内存分配?
Posted
技术标签:
【中文标题】什么是对齐内存分配?【英文标题】:What is aligned memory allocation? 【发布时间】:2010-10-22 05:05:10 【问题描述】:我也想知道 glibc malloc() 是否这样做。
【问题讨论】:
那不是依赖于目标架构吗?它几乎肯定是对齐的...... 【参考方案1】:假设你有这个结构。
struct S
short a;
int b;
char c, d;
;
如果没有对齐,它将像这样在内存中布局(假设是 32 位架构):
0 1 2 3 4 5 6 7
|a|a|b|b|b|b|c|d| bytes
| | | words
问题在于,在某些 CPU 架构上,从内存中加载 4 字节整数的指令仅适用于字边界。因此,您的程序必须使用单独的指令获取 b
的每一半。
但如果内存布局为:
0 1 2 3 4 5 6 7 8 9 A B
|a|a| | |b|b|b|b|c|d| | |
| | | |
然后访问b
变得简单。 (缺点是需要更多内存,因为填充字节。)
不同的数据类型有不同的对齐要求。 char
是 1 字节对齐的,short
是 2 字节对齐的,而 4 字节类型(int
、float
和 32 位系统上的指针)通常是 4 字节对齐。
C 标准要求malloc
返回一个针对任何数据类型正确对齐的指针。
x86-64 上的 glibc malloc
返回 16 字节对齐的指针。
【讨论】:
抱歉,我不明白您所说的“char 通常是 1 字节对齐、short 是 2 字节对齐和 4 字节类型”是什么意思。 @Anni_housie 这只是意味着,大多数系统通常使用 1byte 的内存来存储 char,2bytes 用于存储 short,4bytes 用于 int/float/pointer 等等 或者您可以重新排序结构中的元素,使其首先具有 int,然后是 short,然后是两个字符。这样系统就可以轻松读取它们。 确实,由于成员的对齐方式,结构成员的列出顺序会影响结构的最终大小。 @dan04 感谢您的回答,现在我可以明白为什么在 a 和 b 之间插入 2 个字节的填充。我在某处读到,在您的示例中,在成员 c 之后的末尾还会插入另外 2 个字节的填充以对齐整个结构,为什么需要这样做?【参考方案2】:Alignment 要求指定哪些地址偏移可以分配给哪些类型。这完全取决于实现,但通常基于字长。例如,一些 32 位架构要求所有 int
变量以 4 的倍数开始。在某些架构上,对齐要求是绝对的。在其他(例如 x86)上,无视它们只会带来性能损失。
malloc
需要返回适合任何对齐要求的地址。换句话说,返回的地址可以分配给任何类型的指针。来自 C99 §7.20.3(内存管理功能):
分配时返回的指针 成功被适当地对齐,以便 它可以分配给指向任何 对象类型,然后用于访问 这样的对象或这样的数组 分配空间中的对象(直到 该空间被显式释放)。
【讨论】:
您提供的链接不好。你能再提供一个吗?那个有多个问题!泰【参考方案3】:如果您有特定的内存对齐需求(针对特定硬件或库),您可以查看不可移植的内存分配器,例如 _aligned_malloc()
和 memalign()
。这些可以很容易地在“可移植”接口后面抽象出来,但不幸的是它们是非标准的。
【讨论】:
【参考方案4】:malloc()
文档说:
[...] the allocated memory that is suitably aligned for any kind of variable.
这对于您在 C/C++ 中所做的大多数事情都是正确的。但是,正如其他人指出的那样,存在许多特殊情况并需要特定的对齐方式。例如,Intel 处理器支持 256 位类型:__m256
,malloc()
肯定不会考虑到这一点。
同样,如果您想为要分页的数据分配内存缓冲区(类似于mmap()
返回的地址等),那么您可能需要一个非常大的对齐方式,如果@ 987654326@ 是返回始终与此类边界对齐的缓冲区。
在Linux或其他Unix系统下,建议你使用posix_memalign()
函数:
int posix_memalign(void **memptr, size_t alignment, size_t size);
这是满足此类需求的最新功能。
【讨论】:
以上是关于什么是对齐内存分配?的主要内容,如果未能解决你的问题,请参考以下文章
分配粒度和内存页面大小(x86处理器平台的分配粒度是64K,内存页是4K,所以section都是0x1000对齐,硬盘扇区大小是512字节,所以PE文件默认文件对齐是0x200)