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

2016-12-04  本文已影响61人  mx乐乐

对象的内存布局

在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类型的。

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

上一篇 下一篇

猜你喜欢

热点阅读