脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - 一文带你搞懂Golang结构体内存布局

一文带你搞懂Golang结构体内存布局

2022-11-29 11:201个俗人 Golang

结构体在Go语言中是一个很重要的部分,在项目中会经常用到。这篇文章主要带大家看一下结构体在内存中是怎么分布的?通过对内存布局的了解,可以帮助我们写出更优质的代码。感兴趣的小伙伴们可以参考借鉴,希望对大家能有

前言

结构体在Go语言中是一个很重要的部分,在项目中会经常用到,大家在写Go时有没有注意过,一个struct所占的空间不一定等于各个字段加起来的空间之和,甚至有时候把字段的顺序调整一下,struct的所占空间不一样,接下来通过这篇文章来看一下结构体在内存中是怎么分布的?通过对内存布局的了解,可以帮助我们写出更优质的代码。感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

结构体内存布局

结构体大小

结构体实际上就是由各种类型的数据组合而成的一种符合数据类型,一个结构体变量的大小是由结构体中的字段决定。结构体和它所包含的数据在内存中是以连续块的形式存在的。我们可以借助unsafe.Sizeof方法,来获取:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main
 
import (
    "fmt"
    "unsafe"
)
 
type Test struct {
    T1 int8 // 1
    T2 int8 // 1
    T3 int8 // 1
}
func main() {
    var t Test
    fmt.Println(unsafe.Sizeof(t)) //3 bytes
 
}

内存对齐

不同类型的变量占用内存大小是不一样的,但是cpu每次读取的内存长度是固定的(比如cpu是64位的,一次可以从内存中读取64位的数据,即8个字节),为了cpu能高效的读写数据,编译器会把各种类型的数据放在合适的地址,而不是顺序的一个接一个的排放,并占用合适的长度,这就是内存对齐。每种类型的对齐值就是它的对齐边界。

示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main
 
import (
    "fmt"
    "unsafe"
)
type Test struct {
    a int8 // 1
    b int64 // 8
    c int32 // 4
}
type Test2 struct {
    a int8 // 1
    b int32 // 4
    c int64 // 8
}
func main() {
    var t Test
    fmt.Println(unsafe.Sizeof(t)) // 24
    var t2 Test2
    fmt.Println(unsafe.Sizeof(t2))// 16
}

通过上面示例,我们可以看到两个结构体中3个字段类型相同,当排列顺序发生变化时,总的内存大小也会发生变化。下面我们来一起分析一下:

如果没有内存对齐,那结构体各个字段在内存中是紧密排列的,如t1内存布局示意图如下:

一文带你搞懂Golang结构体内存布局

因为b这个字段需要8个字节,所以会有一个字节的数据排列到第2个字中。如果程序想要读取b字段的数据,那么CPU需要两次读取才能获取到完整的数据,这样就会影响了程序的性能。

所以,为了能让CPU减少一次获取的时间,Go编译器会帮你把struct结构体做数据的对齐,以便CPU可以一次将该数据从内存中读取出来。重新排列后内存布局结构示意图如下:

一文带你搞懂Golang结构体内存布局

其中有13个字节是真正存储数据的,而灰色的11个字节则是为了对齐而填充上的,不存储任何数据,所以才会比没有对齐排列时多出11个字节。

虽然通过对齐填充的方式提高了CPU读写数据的效率,但是这些填充内存确实有点浪费空间,那有没有办法既可以既可以做到内存对齐保证CPU读写效率又能减少浪费内存空间呢?

那就是调整struct字段的顺序,我们在来看一下t2结构体的字段内存布局结构示意图如下:

一文带你搞懂Golang结构体内存布局

这样重新排列后,只占了16个字节,比上面那种方式少了8个字节。由此可知,对结构体字段的重新排列会让结构体更节省内。

总结

本篇文章我们一起学习了Go 语言中的内存对齐,主要内容如下:

  • 结构体是占用一块连续的内存,一个结构体变量的大小是由结构体中的字段决定。
  • unsafe.Sizeof(x) 返回了变量x的内存占用大小。
  • 两个结构体,即使包含变量类型的数量相同,但是位置不同,占用的内存大小也不同,由此引出了内存对齐。
  • 对结构体字段的重新排列会让结构体更节省内。

到此这篇关于一文带你搞懂Golang结构体内存布局的文章就介绍到这了,更多相关Golang结构体内存布局内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://juejin.cn/post/7156141293188415518

延伸 · 阅读

精彩推荐
  • GolangGo项目的目录结构详解

    Go项目的目录结构详解

    这篇文章主要介绍了Go项目的目录结构,对基础目录做了讲解,对项目开发中的其它目录也一并做了介绍,需要的朋友可以参考下 ...

    junjie19722019-11-28
  • GolangGolang学习笔记之延迟函数(defer)的使用小结

    Golang学习笔记之延迟函数(defer)的使用小结

    这篇文章主要介绍了Golang学习笔记之延迟函数(defer),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...

    学生黄哲4812020-05-21
  • Golanggolang http连接复用方法

    golang http连接复用方法

    今天小编就为大家分享一篇golang http连接复用方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    liliangcsdn15692020-05-26
  • Golangmac下安装golang框架iris的方法

    mac下安装golang框架iris的方法

    这篇文章主要介绍了mac下安装golang框架iris的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    李高峰的博客11032021-02-07
  • Golang浅谈golang并发操作变量安全的问题

    浅谈golang并发操作变量安全的问题

    这篇文章主要介绍了浅谈golang并发操作变量安全的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    思维的深度6472021-03-17
  • Golang如何用go-zero 实现中台系统

    如何用go-zero 实现中台系统

    这篇文章主要介绍了如何用go-zero 实现中台系统,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    jackluo6432021-03-04
  • GolangGo语言kylin任务自动化实例详解

    Go语言kylin任务自动化实例详解

    这篇文章主要为大家介绍了Go语言kylin任务自动化实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    爱吃红薯粉7152022-10-17
  • Golang一百行Golang代码实现简单并发聊天室

    一百行Golang代码实现简单并发聊天室

    这篇文章主要为大家详细介绍了一百行Golang代码如何实现简单并发聊天室,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 ...

    Go-Bluer5162020-05-27