C++ 程序员面试时一个经常被问到的问题就是对象内存大小. 对象内存大小的影响因素有很多: static 成员变量, 虚函数, 继承, 内存补齐等, 其中内存补齐是最常被问到的概念, 今天我们就来看看 C++ 对象的内存补齐.
先来看看最基本的对象内存计算规则: 对象的内存大小为成员变量的内存之和, 成员函数不占内存, 无成员变量的对象大小为 1 字节. 如下图中, 对象 a 的内存大小为 val0,val1 两个 int 型 (4 字节) 成员变量的和, 即 8 字节.
但是咱们再来看看下图中对象的内存, 成员变量为 1 个 char 类型(1 字节),1 个 short 类型(2 字节),1 个 int 类型(4 字节). 按上述规则计算, 对象 a,b 内存大小均为 7 字节. 但实际情况却是 a 为 8 字节, b 为 12 字节. 造成这一现象的原因就是对象的内存补齐.
C++ 的内存补齐主要遵循两条规则:
1, 成员变量的偏移量必须为该变量自身大小的整数倍;
2, 对象内存的大小为最大成员变量大小的整数倍;
这里先解释下偏移量的概念: 偏移量即是指变量的首位内存地址相对起始内存地址的位置偏移量, 起始内存地址为对象的内存起始位置. 并且第一个成员变量的偏移量为 0. 下面我们来分析一下第二张图中两个对象的实际内存情况.
首先来看第一个对象 a 的内存情况, a 有三个成员变量依次为 ch0,sh0,val0.ch0 占用 1 个字节, 偏移量为 0.short 类型的 sh0 占用 2 个字节, 根据规则 1,sh0 的偏移量需为 2 的整数倍, 故需要补齐 1 个字节, 从偏移量为 2 的内存地址开始保存变量 sh0. 同样地, int 类型的 val0 占用 4 个字节, 偏移量为 4. 最终对象 a 的内存大小为 8 字节.
而对于对象 b, 三个成员变量依次为 ch0,val0,sh0.ch0 占用 1 个字节, 偏移量为 0;val0 占用 4 个字节, 偏移量为 4, 故需补齐 3 个字节; sh0 占用 2 个字节, 偏移量为 8, 无需补齐. 此时共占用 10 个字节, 而对于对象 b 的最终内存大小, 为最大成员变量 val0(int 型)的整数倍, 即 12 字节. 故需要在对象 b 的最后位置再补齐 2 个字节.
另外, 宏 #pragma pack (n)可以强制设定偏移量为 n 或自身内存大小中较小值的整数倍, n 为 1 时即设置为无内存补齐.
以上即为 C++ 对象内存补齐的全部内容. 对于开头说到的 static 成员变量, 虚函数对内存大小的影响, 用一句话可以概括为: static 成员变量不占用内存, 对象有虚函数时 (不论数量) 对象的整体内存大小需要增加一个指针 (虚函数表指针) 的内存大小. 而对于继承对内存的影响则较为复杂, 有单一继承, 多重继承, 重复继承, 虚继承等多种不同情况, 后续另起一篇说明.
来源: http://www.jianshu.com/p/021031792730