Golang的内存对齐

先看一个结构体

// 写法一
type T1 struct {
    a int8
    b int64
    c int16
}

// 写法二
type T2 struct {
    a int8
    c int16
    b int64
}

对于这两个结构体,都有a、b、c三个定义完全一样的字段,只是在定义结构体的时候字段顺序不一样而已,那么两种写法有什么影响吗?

对于新手来说,感觉着没有什么区别的,只是一个书写顺序不同而已,但对于go编译器来说,则有着很大的区别,特别是在不同架构上(32位/64位)的编译器,在一定程度上对内存的使用大小和执行效率有着一定的不同。这里的主要知识点就是golang语言中的内存对齐概念(alignment guarantee),https://gfw.go101.org/article/memory-layout.html

类型的尺寸和结构体字节填充(structure padding)

Go白皮书只对以下种类的类型的尺寸进行了明确规定

类型种类                  尺寸(字节数)
------                   ------
byte, uint8, int8        1
uint16, int16            2
uint32, int32, float32   4
uint64, int64            8
float64, complex64       8
complex128               16
uint, int                取决于编译器实现。通常在
                         32位架构上为4,在64位
                         架构上为8。
uintptr                  取决于编译器实现。但必须
                         能够存下任一个内存地址。

Go白皮书没有对其它种类的类型的尺寸最初明确规定。 请阅读值复制成本一文来获取标准编译器使用的各种其它类型的尺寸。

标准编译器(和gccgo编译器)将确保一个类型的尺寸为此类型的对齐保证的倍数。

为了满足上一节中规定的地址对齐保证要求,Go编译器可能会在结构体的相邻字段之间填充一些字节。 这使得一个结构体类型的尺寸并非等于它的各个字段类型尺寸的简单相加之和。

下面是一个展示了一些字节是如何填充到一个结构体中的例子。 首先,从上面的描述中,我们已得知(对于标准编译器来说):

  • 内置类型int8的对齐保证和尺寸均为1个字节; 内置类型int16的对齐保证和尺寸均为2个字节; 内置类型int64的尺寸为8个字节,但它的对齐保证在32位架构上为4个字节,在64位架构上为8个字节。
  • 下例中的类型T1T2的对齐保证均为它们的各个字段的最大对齐保证。 所以它们的对齐保证和内置类型int64相同,即在32位架构上为4个字节,在64位架构上为8个字节。
  • 类型T1T2尺寸需为它们的对齐保证的倍数,即在32位架构上为4n个字节,在64位架构上为8n个字节。
type T1 struct {
    a int8

    // 在64位架构上,为了让下一个字段b的地址为8字节对齐,
    // 需在在字段a这里填充7个字节。在32位架构上,为了让
    // 字段b的地址为4字节对齐,需在这里填充3个字节。

    b int64
    c int16

    // 为了让类型T1的尺寸为T1的对齐保证的倍数,
    // 在64位架构上需在这里填充6个字节,在32架构
    // 上需在这里填充2个字节。
}
// 类型T1的尺寸在64位架构上位24个字节(1+7+8+2+6),
// 在32位架构上为16个字节(1+3+8+2+2)。
// 以保存每个字段都是8(64位架构)或者4(32位架构)的的整数倍

type T2 struct {
    a int8

    // 为了让下一个字段c的地址为2字节对齐,
    // 需在字段a这里填充1个字节。

    c int16

    // 在64位架构上,为了让下一个字段b的地址为8字节对齐,
    // 需在字段c这里填充4个字节。在32位架构上,不需填充
    // 字节即可保证字段b的地址为4字节对齐的。

    b int64
}
// 类型T2的尺寸在64位架构上位16个字节(1+1+2+4+8),
// 在32位架构上为12个字节(1+1+2+8)。

从这个例子可以看出,尽管类型T1T2拥有相同的字段集,但是它们的尺寸并不相等。每个字段的大小都要受下一个字段大小的影响,以方便下个字段对齐。所以建议在开发中,字段占用空间小的放在前面。

T1的内存对齐
T2的内存对齐

一个有趣的事实是有时候一个结构体类型中零尺寸类型的字段可能会影响到此结构体类型的尺寸。 请阅读此问答获取详情。

主要记住使用时,Type size的值越小越好,这样就可以对结构体进行一些内存大小优化了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,941评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,397评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,345评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,851评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,868评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,688评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,414评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,319评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,775评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,945评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,096评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,789评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,437评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,993评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,107评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,308评论 3 372
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,037评论 2 355

推荐阅读更多精彩内容