阅读《游戏引擎架构》(四)

对象的内存布局

在class和struct中,编译器不会把数据程序员紧凑的包裹在一起,因为每种数据都有其天然的对齐方式,供CPU高效的从内存读/写。对齐方式即内存地址为对齐字节大小的倍数,另外编译器可能会为了数组的对齐,会在末端加入填充,以下是32位系统下各个类型的大小(单位:字节):
int:4字节;float:4字节;double:8字节;bool:1字节;char:1字节;short:2字节;long:4字节或者8字节

例如下图:

struct InefficientPacking
{
  U32   mU1;    //32位
  F32   mF2;    //32位
  U8    mB3;    //8位
  I32   mI4;    //32位
  bool  mB5;    //8位
  char* mP6;    //32位
};
混合数据成员大小导致低效的struct包裹

现在,我们重新考虑上图的中struct InefficientPacking布局里的空隙。在class或struct中,当把较小的数据类型(如8位的bool)放置于较大类型(如32位的float)之间,编译器会加入填充(空隙),以保证所有成员都是正常地对齐的。当声明数据结构时,认真对待对齐和包裹是个好习惯。如以下代码及图所示,只需简单地重新排列上述例子中的成员,就能省去了一些浪费了的填充空间。

struct MoreEfficientPacking
{
  U32   mU1;    //32位(4字节对齐)
  F32   mF2;    //32位(4字节对齐)
  I32   mI4;    //32位(4字节对齐)
  char* mP6;    //32位(4字节对齐)
  U8    mB3;    //8位(1字节对齐)
  bool  mB5;    //8位(1字节对齐)
};
小成员组合在一起,包裹更高效

在内存布局上,C++的类有别于C的结构之处有二——继承与虚函数。
当B类继承自A类,内存里B类的数据成员会紧接A类数据成员之后,如图所示。

继承对类布局的影响

需要说明的是,当class中有虚函数的时候,或者是继承的类中有虚函数的时候,通常会在类的布局最前端加入一个虚表指针,它指向名为虚函数表的一个数据结构,因为指针是int类型的。

了解内存布局的意义是,当我们写类和结构体的时候,最优化的处理方式是自己按照内存布局规则把数据排列好,从而可以降低类或者结构体所占的大小。

推荐阅读更多精彩内容

  • 1. 结构体和共同体的区别。 定义: 结构体struct:把不同类型的数据组合成一个整体,自定义类型。共同体uni...
    breakfy阅读 1,901评论 0 21
  • 1. C++基础知识点 1.1 有符号类型和无符号类型 当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值...
    Mr希灵阅读 16,708评论 3 81
  • 一个博客,这个博客记录了他读这本书的笔记,总结得不错。《深度探索C++对象模型》笔记汇总 1. C++对象模型与内...
    Mr希灵阅读 4,845评论 0 13
  • iOS面试小贴士 ———————————————回答好下面的足够了------------------------...
    不言不爱阅读 1,576评论 0 7
  • ———————————————回答好下面的足够了---------------------------------...
    恒爱DE问候阅读 1,368评论 0 4
  • 最近两次大规模线下宣传# 本周五 发传单 地点 1234餐 时间 周五11:50-12:30 人员:一二三四餐=4...
    coalade阅读 71评论 0 0
  • 今天是周一,在安排好工作之余抽空用电脑把整本书读完了,我喜欢PDF的形式看书,就像读书时代阅读文献一样,一篇篇文献...
    黄了个豆阅读 99评论 0 0
  • 和老妈说月底回家只能呆2天,周六到长春,周日回长春,老妈感觉匆忙,并表示你到家就得睡,睡醒了就走了,回去上班还很累...
    老张的小可爱阅读 101评论 0 0
  • 宴平虽好,不贪纷扰。 乘风约归,庶子相追? 愁心寄月,勿忘南飞。
    楚地小生阅读 128评论 0 1