我试图解释在Linux中对我的应用程序采取的内存。我做了一个基本测试并发现如果我们新建一些内存,它会为一个新的内存分配至少32个字节。
这是我的代码。
#include <iostream>
#include <stdlib.h>
using namespace std;
int main(int argc, const char** argv)
{
int iBlockSize = atoi(argv[1]);
int iBlockCount = atoi(argv[2]);
for (int i = 0 ; i < iBlockCount ; i++)
{
cout << (int*)(new char[iBlockSize]) << endl;
}
return 0;
};
当我执行./a.out 8 100
时,它给出了以下结果。
....
....
....
0xf6db10
0xf6db30
0xf6db50
0xf6db70
0xf6db90
0xf6dbb0
0xf6dbd0
0xf6dbf0
0xf6dc10
0xf6dc30
0xf6dc50
0xf6dc70
我得到的所有内存都有32个字节的间隙。
到24(BlockSize)它是一样的。如果超过24,则为48字节。
./ a.out 25 100
....
....
....
0x18b30c0
0x18b30f0
0x18b3120
0x18b3150
0x18b3180
0x18b31b0
0x18b31e0
0x18b3210
0x18b3240
0x18b3270
0x18b32a0
当我测试更大尺寸时;我们发现我们得到的内存增加了16个字节的块,至少保留了8个字节的开销。
我的问题是,
答案 0 :(得分:6)
C语言中的内存分配必须为所有基本类型返回适当对齐的内存[0]。
这意味着内存分配通常会为您提供至少8字节对齐的内存,因此您可以在其中存储doubles
。
因此,当您请求1字节内存时,由于对齐要求,您将使用至少8个字节。 在64位系统上,内存分配通常会为您提供16字节对齐的内存,因为这些系统通常具有16字节大型(SSE向量)
此外,内存分配器需要一些空间用于其管理数据,例如分配的大小。 根据实现情况,可以在用户分配的内存块之前或之后放置此数据。
[0]当地址/指针是访问它的大小的倍数时,内存是对齐的,某些cpus不支持未对齐访问(例如sparc),其他(如x86)如果你这样做会有性能损失
答案 1 :(得分:2)
C ++标准中与该主题相关的几行;我认为它简要地描述了这不是错误的行为。
C ++程序中定义的任何分配和/或释放函数, 包括库中的默认版本,应符合 3.7.4.1和3.7.4.2中规定的语义。 ...
3.7.4.1分配函数 ...返回的指针应适当对齐,以便它可以转换为任何指针 具有基本对齐要求的完整对象类型(3.11) 和......
3.11对齐对象类型具有对齐要求(3.9.1,3.9.2),这些要求对可以分配该类型的对象的地址施加限制。对齐是实现定义的 整数值,表示连续之间的字节数 可以分配给定对象的地址。 ...
答案 2 :(得分:1)
我找到了这篇文章
https://software.intel.com/en-us/articles/align-and-organize-data-for-better-performance
它说“如果使用向量指令加载和存储来访问数据,则将数据对齐在16字节边界上。”
所以看起来这是由glibc做出的对齐决定