序
Golang 中的结构或 struct 是用户定义的类型,允许将可能不同类型的项分组/组合为单一类型。
可以说是一个不支持继承但支持组合的轻量级类。
我们使用 Golang 编写代码的时候,你肯定使用过struct。
但是,你可能不知道的是,通过简单地重新排序结构中的字段,可以极大地提高 Go 程序的速度和内存使用率!
示例演示
- type EmployeeStruct struct {
- IsPublic bool
- Age int64
- Status bool
- Name string
- Image float32
- }
复制代码 我们来看一下Employee结构体的内存大小:
- IsPublic(boolean) 1 字节
- Age(int64) 8 字节
- Status(boolean) 1 字节
- Name(string) 16 字节
- Image(float32) 4 字节
总计: 30 字节
通过unsafe.Sizeof检查一下:- package mainimport ( "fmt" "unsafe")type EmployeeStruct struct {
- IsPublic bool
- Age int64
- Status bool
- Name string
- Image float32
- }func main() { var employee EmployeeStruct fmt.Println(unsafe.Sizeof(employee))}
复制代码 执行后输出: 48字节,为什么呢?
处理器类型
我们知道CPU 分为32位、34位,但是,它是如何运作的呢?

想象一下我们有一个 64 位的 CPU,每个时钟周期传输 64 位数据的能力。
时钟周期是CPU处理一个信息需要多少时间,CPU 32位在1个周期内转换4字节数据,CPU 64位在1个周期内转换8字节数据(32位= 4字节,64位= 8字节)
上面我们定义的EmployeeStruct结构体,并且计算得到了每个字段在内存中占用的字节数。下面我们看CPU处理信息需要多少时间呢?
先来看下面的一张图:

图里面6个周期,每个周期有八个盒子,表示是CPU处理能力,为 8 字节
- 周期1
第一个属性是IsPublic,数据类型为布尔型,bool 的大小为 1 个字节。因此,当前周期 1 由属性IsPublic(bool ~ 1 byte)填充。
下一个属性是Age,数据类型为int64,int64的大小是8字节,由于第1个周期的剩余内存大小只有7个字节,因此第1个周期无法填充Age属性,因此,会进入第2个周期,但是,“剩余的空间呢,怎么办?”。
- 周期2
第2个周期由Age属性填充,数据类型为int64,大小为8字节,刚好填充满。
- 周期3
第三个属性Status,数据类型为bool,大小为1字节,填充(bool~1 byte),剩余内存大小为7字节,然后,下一个属性是Name,类型为字符串,大小为 16 字节,与周期1的情况相同,因为没有足够的空间容纳下一个属性,所以将在下一个周期中进入。所以意味着有7个字节的内存被浪费了。
- 周期 4 和周期 5
第四个是Name,数据类型为字符串,大小为16字节。从图上面看,它将在两个周期中填充,周期 4 中填充 8 个字节,周期 5 中填充 8 个字节。
- 周期6
最后一个属性是Image, 数据类型为float32,大小为4字节,浪费剩余的 4 个字节。
最后通过计算统计:
总时钟周期 = 6 个时钟周期
结构体大小 = 48 字节
浪费的总内存 = 18 字节
所以我们在开发的时候,如果对于一个比较大的数据结构体来说,可能会使结构体的大小变得更大。
那么,如何解决呢?
实际上我们可以根据数据类型的大小来组成序列,最简单的方法是:
按元素内存大小的降序排列字段
- type EmployeeStruct struct {
- Name string
- Age int64
- Image float32
- IsPublic bool
- Status bool
- }
复制代码 这个时候我们再来看一下时间周期:

- 周期 1 和周期 2
第一个属性是Name,数据类型为字符串,大小为16字节。因此,它将在两个周期中填充,周期 1 中填充 8 个字节,周期 2 中填充 8 个字节。
- 周期3
第3个周期由Age属性填充,数据类型为int64,大小为8字节
- 周期4
下一个属性是Image,数据类型为float32,大小为4字节。因此,当前周期 4 由属性 Image ( float32 ~ 4 字节)填充,剩余大小为 4 字节。
下一个属性是IsPublic(bool ~ 1 字节)和 Status(bool ~ 1 字节)。因为最后两个属性的总大小只有2个字节,所以我们可以将其放在循环4中。这样一来,循环4就被Image ( float32 ~ 4字节)、IsPublic (bool ~ 1字节)、Status(bool~1 字节)填满了,仅浪费 2 字节内存。
最后通过计算统计:
总时钟周期 = 4 个时钟周期
结构体大小 = 32 字节
浪费的总内存 = 2 字节
- package mainimport ( "fmt" "unsafe")type EmployeeStruct struct {
- Name string
- Age int64
- Image float32
- IsPublic bool
- Status bool
- }func main() { var employee EmployeeStruct fmt.Println(unsafe.Sizeof(employee)) // output: 32}
复制代码 结束
所以我们在开发的时候,重新排序结构字段是可以提高应用程序的内存使用率和运行速度的。
转载:风向阅读 - Golang 开发技巧 - 简单的数据对齐可提高程序速度和内存使用率
地址:https://www.aiweimeng.top/archives/56.html
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |