Memory Layout
今天做了一个简单的测试,简单地探究了一下GCC下的Memory Layout。
程序的运行环境如下:
1 | Linux indy2-login0 3.10.0-327.36.3.el7.x86_64 #1 SMP Mon Oct 24 16:09:20 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux |
程序如下:
1 |
|
采用gcc编译并运行这段程序,得到了如下的结果:
1 | i 4 00007fffffffdc7c |
可以看到,对于一个primitive,在该测试环境下,变量在stack上由高向低分配。对于一个结构体内部,所有的变量则在结构体对应的地址空间上由低向高顺序分配。
这里注意到,对于var这个由1个int,2个short,2个double组成的结构体,理论上,这个结构体应该占据24byte的空间,然而实际上var这个结构体占据了32byte。这是由于GCC下会对该程序进行一个内存对齐(alignment)。通常来说,内存总线以字(word, 4byte)为最小单位进行传输。为了避免传输的数据被截断,需要重新指向来获取数据所造成的额外的开销,GCC对这个程序进行了内存对齐的处理。变量s是一个short型变量,在该环境下占2byte。假设紧随其后的double变量d在内存上紧接着s存储,当数据传输过来时,由于以字为单位进行传输,变量d将会被截断,为了恢复变量d需要做额外的处理。因此,在此处s后面,GCC填充了2byte的占位字节,使其称为一个完整的word,而相应的d则紧随其后,在两个齐整的word下存储。这就是为什么var这个结构体使用了比理想状态下更多的空间。
下面我们对于代码进行小小的调整,我们修改var所对应的结构体,将s2变量的位置提升到s之下,其余部分不变:
1 |
|
然后编译执行程序,我们得到的如下的结果:
1 | i 4 00007fffffffdc7c |
此处我们看到,结构体对象var与我们预想的一样,占用了24byte的空间。这是因为简单的重排,使两个short变量s与s1正好占据一个word,避免了各自的对齐从而减少了空间的开销。由此可见,对于C语言中的结构体,在GCC下所有的成员变量会以对应的顺序进行存储,对于无法整齐排列在内存中的变量,会进行内存对齐,通过填充空的占位字节使其占据完整的一个word。通过对于变量顺序的调整,可以减少程序中的内存的使用!