内存对齐、structs和malloc
Memory alignment, structs and malloc
在一个问题中表达我想知道的内容有点困难,所以我会尝试将其分解。
例如,假设我们有以下结构:
struct X {
uint8_t a;
uint16_t b;
uint32_t c;
};
编译器保证永远不会重新排列X成员的顺序,只在必要时添加填充,这是真的吗?换句话说,offsetof(X,a)<offsetof(X,c)?
编译器会在X的成员中选择最大的对齐方式,并使用它来对齐X类型的对象(即,X实例的地址可以被X成员中最大的对齐次数整除),这是真的吗?
由于malloc在分配缓冲区时对我们要存储的对象类型一无所知,它如何为返回的地址选择对齐方式?它是否只是返回一个地址,该地址可以被最大的对齐整除(在这种情况下,无论我们在缓冲区中放入什么结构,内存访问都将始终对齐)?
- 是
- 不,编译器将使用其对目标主机硬件的了解来选择最佳对齐
- 参见问题2
由于malloc在分配缓冲区时对我们要存储的对象类型一无所知,它如何为返回的地址选择对齐方式?
malloc(3)
返回"为任何类型的变量适当对齐的内存。"
它是否只是返回一个地址,该地址可以被最大的对齐整除(在这种情况下,无论我们在缓冲区中放入什么结构,内存访问都将始终对齐)?
是的,但要注意遵守严格的别名规则。
编译器将在最多的情况下在该计算机上执行任何最有益的操作。在大多数平台上,在总线宽度偏移上加载总线宽度值是最快的。
这意味着,通常在32位计算机上,编译器会选择在4字节偏移量上对齐32位数字。在64位计算机上,64位值在8字节偏移上对齐。
在大多数计算机上,较小的值(如8位和16位值)加载较慢。可能它周围的所有4或8个字节都已加载,您需要的字节或两个字节被屏蔽
当您有特殊情况时,您可以通过指定对齐和填充来覆盖编译器。当你知道快速加载并不重要,但你真的想把数据打包时,你可能会这样做。或者当你在选角和工会上玩非常微妙的把戏时。
几乎任何现代计算机上的内存分配例程都会返回至少在平台的总线宽度上对齐的内存(例如4或8字节),甚至更像16字节对齐。
当你调用"malloc"时,你有责任知道你需要的结构的大小。幸运的是,编译器会用"sizeof"告诉你任何结构的大小。这意味着,如果您打包一个结构以节省内存,sizeof将返回比未打包结构更小的值。因此,如果您在它们的大数组中分配小结构,您确实会节省内存。
如果你一次分配一个小的打包结构——那么是的——如果你打包与否,不会有任何区别。这是因为当您分配一些奇怪的小块内存时,分配器实际上会使用比这多得多的内存。它会为您分配一个方便大小的内存块,然后为自己分配一个额外的内存块来跟踪您的分配情况。
这就是为什么如果你关心内存使用并想打包你的结构——你肯定不想一次分配一个。
- 如果没有malloc,链表实现将失败
- malloc() 可能出现内存泄漏
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- 当我尝试加载内核模块时,如何修复C++中的这个 malloc() 错误?
- 在C++中创建队列 - 什么是 malloc 错误?
- 如何在 malloc 内存中初始化非 POD 数据
- 使用 malloc() 时出现意外大小
- C++:在被本地字符串捕获后释放或销毁 malloc'd char *?
- 错误:malloc:对象 0x7f9edf504080 的 *** 错误:未分配正在释放的指针
- 将 malloc 替换为数组
- SIGSEGV on Boost UDP 套接字关闭 - tcache_get at malloc.c.
- Malloc 在使用线程并行化 SSH 调用时存在问题
- 如何将新更改为 malloc?
- 将 malloc 转换为新的正确方法
- Malloc void return char 数组有时不起作用(Terry Davis 对 C++);
- 如何通过 malloc 为队列数组分配内存?
- 正在调试 malloc():新内存损坏
- 我怎样才能代替使用新的使用malloc翻译
- std::memcpy vs std::copy_n for legacy c structs
- 内存对齐、structs和malloc