据我所知,数据对齐是将内存中的64位/ 32位数据块用于CPU性能,我使用的是64位linux机器,我做了一些测试并得到了一些奇怪的结果(我无法解释)行为)。
以下是我使用的结构:
class A {
long l0,l1,l2;
};
class B {
long l0,l1,l2,l3;
};
class C {
long l0,l1,l2,l3,l4;
};
测试:
int main() {
C* newC = new C();
B* newB = new B();
A* newA = new A();
int* i = new int();
std::cout << sizeof(A) << std::endl;
std::cout << sizeof(B) << std::endl;
std::cout << sizeof(C) << std::endl;
std::cout << "C : " << newC << std::endl;
std::cout << "B : " << newB << std::endl;
std::cout << "A : " << newA << std::endl;
std::cout << "i : " << i << std::endl;
delete (i);
delete (newC);
delete (newA);
delete (newB);
return 0;
}
只需将每个对象放入堆中,我在末尾添加了一个指针,以查看newA
所占用的内存
结果如下:
24
32
40
C : 0x603010
B : 0x603040
A : 0x603070
i : 0x603090
3*16 bytes
和newC
的地址之间的 newB
:C是40个字节,已经是64位的倍数,为什么这8个字节更多?
3*16 bytes
和newB
之间的 newA
?? B只有32个字节,我预计:A : 0x603060
2*16 bytes
和newA
?? 的地址之间 i
答案 0 :(得分:4)
当您在堆上分配时,您无法对地址做出任何明确的陈述。
内存分配函数很有可能维护有关已分配块的内联信息,这将影响下一个块的地址,如:
+--------+-------------+--------+-------------+
| header | alloced mem | header | alloced mem | ...
+--------+-------------+--------+-------------+
此外,为了提高效率,这些功能可能会将您的记忆整理为(例如)八或十六的倍数(您仍然不允许使用它,因为您不会知道关于它)。这可能会进一步影响您为分配的内存看到的地址。
的经典案例这些影响你的效果可以看作:
#include <iostream>
#include <cstdlib>
int main (int argc, char *argv[]) {
char *one = new char[std::atoi(argv[1])];
char *two = new char[std::atoi(argv[1])];
std::cout << static_cast<void*>(one) << '\n';
std::cout << static_cast<void*>(two) << '\n';
return 0;
}
和脚本:
#!/usr/bin/bash
for i in {01..37}; do
echo $i $(./qq $i)
done
在我的系统上,输出:
01 0x800102e8 0x800102f8
02 0x800102e8 0x800102f8
:: (all the same address pairs in here and in gaps below)
12 0x800102e8 0x800102f8
13 0x800102e8 0x80010300
::
20 0x800102e8 0x80010300
21 0x800102e8 0x80010308
::
28 0x800102e8 0x80010308
29 0x800102e8 0x80010310
::
36 0x800102e8 0x80010310
37 0x800102e8 0x80010318
当你只分配一个字符时,在两者之间提供高达 16个字节。
保持 16个字节一直到new char[12]
的事实,并且每次在之后添加8个字符时增加8个似乎表示四个字节的头,头+数据的最小十六个字节,头+数据区的八字节分辨率。
请记住,基于我对这些事情往往被写入的方式的了解,而受过教育的猜测,仍然猜测,你不应该依赖它。它可能使用与我的想法完全不同的策略,或者它可能会改变其对更大块的策略。
如果您想知道实际所占类型的空间大小,请创建一个两个数组,并计算x[0]
和x[1]
之间内存地址的差异。您会发现它应该与您从sizeof
获得的相同。
答案 1 :(得分:2)
您不能假设后续调用new将在内存中返回连续的块。
如果您想尝试测试用例,我建议您执行以下操作:
struct D{
C c;
B b;
A a;
}
现在您可以开始打印地址了。但是只有浮点数,我预计没有对齐问题。