详解简单高效的Go struct优化

目录
  • 前言
  • 先来看个例子
  • 内存对齐机制
  • 案例进一步分析
  • 总结

前言

结构体的定义,大家都很熟悉,但想要定义出更节省内存空间的结构体,可不是一件简单的事。

我们必须掌握了Go的结构体内存对齐机制,才能做出相应的优化(节省内存并提高性能)。

先来看个例子

下面定义两个结构体,字段都一样,只是部分字段稍微调整了一下顺序。

但输出的结果,为什么bad占用24字节,而good却只占用16字节呢?一个顺序调整就节省了8个字节,太神奇了

type BadSt struct {
  A int32
  B int64
  C bool
}

type GoodSt struct {
  A int32
  C bool
  B int64
}

func main() {
  bad := BadSt{A: 10, B: 20, C: false}
  fmt.Println(unsafe.Sizeof(bad))
  good := GoodSt{A: 10, B: 20, C: false}
  fmt.Println(unsafe.Sizeof(good))
}
//输出结果:
//24
//16

想要解开这个问题,我们得先来学习一下内存对齐机制,然后再来进一步分析

内存对齐机制

  • 基本概念

为了能让CPU可以更快的存储与读取到各个字段,Go编译器会帮我们把结构体做数据的对齐。所谓的数据对齐,是指内存地址是所存储数据大小的整数倍(按字节为单位),以便CPU可以一次将该数据从内存中读取出来,减少了读取次数。编译器通过在结构体的各个字段之间填充一些空白已达到对齐的目的

  • CPU访问内存

CPU 访问内存时,并不是逐个字节访问,而是以机器字(word)为单位进行访问。比如 64位CPU的字长(word size)为8bytes,那么CPU访问内存的单位也是8字节,每次加载的内存数据也是固定的若干字长,如8words(64bytes)、16words(128bytes)等

  • 对齐系数

不同硬件平台占用的大小和对齐值都可能是不一样的,每个特定平台上的编译器都有自己的默认"对齐系数",32位系统对齐系数是4,64位系统对齐系数是8

不同类型的对齐系数也可能不一样,使用Go语言中的unsafe.Alignof函数可以返回相应类型的对齐系数,对齐系数都符合2^n这个规律,最大也不会超过8

func main() {
  fmt.Printf("bool:   %d\n", unsafe.Alignof(bool(true)))
  fmt.Printf("string: %d\n", unsafe.Alignof(string("a")))
  fmt.Printf("int:    %d\n", unsafe.Alignof(int(0)))
  fmt.Printf("int32:  %d\n", unsafe.Alignof(int32(0)))
  fmt.Printf("int64:  %d\n", unsafe.Alignof(int64(0)))
  fmt.Printf("float64:  %d\n", unsafe.Alignof(float64(0)))
  fmt.Printf("float32:%d\n", unsafe.Alignof(float32(0)))
}
//输出结果:
//bool:   1
//string: 8
//int:    8
//int32:  4
//int64:  8
//float64:8
//float32:4
  • 对齐原则
  • 结构体变量中成员的偏移量必须是成员大小的整数倍
  • 整个结构体的内存大小必须是最大字节的整数倍(结构体的内存占用是1/4/8/16byte…)

案例进一步分析

  • BadSt结构体,占用24个字节

type BadSt struct {
  A int32
  B int64
  C bool
}

分析过程:

  • 字段A 4字节:先计算偏移量,最开头下标为0,0%4=0,正好整除,先占用4个字节;
  • 字段B 8字节:下标4-7,对8都不能整除,则填充空白,下标8可以整除,所以下标8-15 8个字节为字段B的存储使用;
  • 字段C 1字节:下标16,对1可以整除,所以下标16则用作字段C的存储;
  • 最后,该结构体字段最大字节为8且目前已占用17字节,要保证是整数倍,所以最后面需要填充7个字节,占满24字节,才能满足条件(对齐原则2)。
  • GoodSt结构体,占用16个字节

type GoodSt struct {
  A int32
  C bool
  B int64
}

分析过程:

  • 字段A 4字节:先计算偏移量,最开头下标为0,0%4=0,正好整除,先占用4个字节;
  • 字段C 1字节:下标4,对1可以整除,所以下标4则用作字段C的存储;
  • 字段B 8字节:下标5-7,对8都不能整除,则填充空白,下标8可以整除,所以下标8-15 8个字节为字段B的存储使用;
  • 最后,该结构体字段最大字节为8且目前已占用16字节,正好是整数倍,所以后面不再需要填充空白了。

总结

掌握了内存对齐机制后,结构体struct的优化,是不是也会觉得原来如此简单高效呀,调整下字段顺序,效果立竿见影(简单理解,就是将对齐系数小的字段,尽可能的放在一起)。

内存对齐其实就是典型的空间换时间的方式,来达到优化的目的。牢记对齐原则,对实际场景进行分析,一切都会很变得清晰明了。

以上就是详解简单高效的Go struct优化的详细内容,更多关于Go struct优化的资料请关注我们其它相关文章!

(0)

相关推荐

  • Go遍历struct,map,slice的实现

    遍历结构体 如何实现遍历结构体字段? 好吧,言归正传!举个例子: demo1: package main import ( "fmt" "reflect" ) type Student struct { name string age int } func main() { v := reflect.ValueOf(Student{"乔峰", 29}) count := v.NumField() for i := 0; i < count;

  • golang中json和struct的使用说明

    1.返回json响应结果 在struct的字段后面加入json:"key"可以进行json格式输出,其中key为json的键名 type SuccessResponse struct { Code int `json:"code"` Msg string `json:"msg"` Data interface{} `json:"data"` } func SuccessRsp(ctx *gin.Context, data in

  • Go 通过结构struct实现接口interface的问题

    目录 一.通过结构(struct) 实现 接口(interface) 二.代码示例 一.通过结构(struct) 实现 接口(interface) 1.在了解iris框架的时候,经常看到有这样去写的使用一个空结构体作为接收器,来调用方法,有点好奇这样做有什么意义. 解释:在 Go 语言中,一个 struct 实现了某个接口里的所有方法,就叫做这个 struct 实现了该接口. 2.空结构体有以下几大特点 A.不占用内存地址. B.地址不变 3.首先我们知道interface定义的是抽象方法,而下

  • golang struct json tag的使用以及深入讲解

    目录 一.sturct json tag的使用 1.tag格式说明 2.具体使用格式说明 二.源码角度的设计处理过程 1.typeFields 2.encode 三.总结 一.sturct json tag的使用 1.tag格式说明 struct json tag主要在struct与json数据转换的过程(Marshal/Unmarshal)中使用. json的tag格式如下: Key type  `json:"name,opt1,opt2,opts..."` 说明: 变量必须是可导出

  • golang中的struct操作

    struct是实现面向对象的重要技术,基本上都跟类型声明type name underlying-type结合使用. struct是值类型,所以它的零值是所有成员的零值.由于值类型在作为函数参数时的局限性,所以经常配合指针一起使用. 声明 type Employee struct { ID int Name string Address string } 一行一个成员,中间没有逗号或分号,大写的成员可以在包外访问. 如果类型相同,也可以考虑定义在一行,例如 type Employee struc

  • Go如何实现json字符串与各类struct相互转换

    目录 json字符串与各类struct相互转换 简单总结 结构体转换为JSON字符串的一个坑 来看一下这个例子 json字符串与各类struct相互转换 不废话了都在代码中了 package main import ( "fmt" "reflect" "encoding/json" "strings" ) type Class struct { Grade int `json:"grade"` //年级 C

  • 详解简单高效的Go struct优化

    目录 前言 先来看个例子 内存对齐机制 案例进一步分析 总结 前言 结构体的定义,大家都很熟悉,但想要定义出更节省内存空间的结构体,可不是一件简单的事. 我们必须掌握了Go的结构体内存对齐机制,才能做出相应的优化(节省内存并提高性能). 先来看个例子 下面定义两个结构体,字段都一样,只是部分字段稍微调整了一下顺序. 但输出的结果,为什么bad占用24字节,而good却只占用16字节呢?一个顺序调整就节省了8个字节,太神奇了 type BadSt struct { A int32 B int64

  • 详解C++11中模板的优化问题

    1. 模板的右尖括号 在泛型编程中,模板实例化有一个非常繁琐的地方,那就是连续的两个右尖括号(>>)会被编译器解析成右移操作符,而不是模板参数表的结束.我们先来看一段关于容器遍历的代码,在创建的类模板 Base 中提供了遍历容器的操作函数 traversal(): // test.cpp #include <iostream> #include <vector> using namespace std; template <typename T> class

  • AngularJS 双向数据绑定详解简单实例

    angular的双向数据绑定,个人理解是,通过model建立数据模型,那么视图上的数据就会对应存储在angular程序里,视图上的数据变化会同步到model,model的数据改变也会同步到视图. 下面的demo演示: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>hello, AngularJS!</titl

  • AngularJS  双向数据绑定详解简单实例

    angular的双向数据绑定,个人理解是,通过model建立数据模型,那么视图上的数据就会对应存储在angular程序里,视图上的数据变化会同步到model,model的数据改变也会同步到视图. 下面的demo演示: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>hello, AngularJS!</titl

  • 详解nginx反向代理配置及优化

    前言: 由于服务器apache抗不住目前的并发.加上前端squid配置后,问题依然无法解决.而页面程序大部分是动态.无法使用fastcgi来处理.因此想使用nginx做为反向代理apache.整个配置安装过程很简单.在考虑高并发的情况下,在安装前就做了些优化.目前配置能抗住3000以上并发.好像不是特别大哦?呵~~ 但足以~~ 只是还有少量499问题..期待有人跟我讨论解决 第1部分:安装 1 建立用户及组 /usr/sbin/groupadd www /usr/sbin/useradd -g

  • 详解C++程序中定义struct结构体的方法

    什么是结构体? 简单的来说,结构体就是一个可以包含不同数据类型的一个结构,它是一种可以自己定义的数据类型,它的特点和数组主要有两点不同,首先结构体可以在一个结构中声明不同的数据类型,第二相同结构的结构体变量是可以相互赋值的,而数组是做不到的,因为数组是单一数据类型的数据集合,它本身不是数据类型(而结构体是),数组名称是常量指针,所以不可以做为左值进行运算,所以数组之间就不能通过数组名称相互复制了,即使数据类型和数组大小完全相同. 结构体的定义 定义结构体使用struct修饰符,例如: struc

  • 详解vue-cli之webpack3构建全面提速优化

    前言 伴随着vue的全球化,已经各种vue的组件框架越来越完善,从早期的element-ui到vux,iview等越来越多高质量的项目,使用vue进行前端构建已然是一件工程化,模块化,敏捷化的事情 在这其中,相信很多人都会选择官方的vue-cli初始化工程模板,然后通过引入第三方组件框架和工具的方式进行开发构建,我个人也十分推崇这种做法.但是vue-cli初始化的项目模板毕竟是面向所有开发者的,在兼容性方面会有一定妥协.相信很多人都已经搜索过各类的webpack构建优化文章,但是很多不是版本太老

  • 详解多页应用 Webpack4 配置优化与踩坑记录

    前言 最近新起了一个多页项目,之前都未使用 webpack4,于是准备上手实践一下.这篇文章主要就是一些配置介绍,对于正准备使用 webpack4 的同学,可以做一些参考. webpack4 相比之前的 2 与 3,改变很大.最主要的一点是很多配置已经内置,使得 webpack 能"开箱即用".当然这个开箱即用不可能满足所有情况,但是很多以往的配置,其实可以不用了.比如在之前,压缩混淆代码,需要增加uglify插件,作用域提升(scope hosting)需要增加ModuleConca

  • 详解免费高效实用的.NET操作Excel组件NPOI(.NET组件介绍之六)

    很多的软件项目几乎都包含着对文档的操作,前面已经介绍过两款操作文档的组件,现在介绍一款文档操作的组件NPOI. NPOI可以生成没有安装在您的服务器上的Microsoft Office套件的Excel报表,并且在后台调用Microsoft Excel ActiveX更有效率;从Office文档中提取文本,以帮助您实现全文索引功能(大多数时候,此功能用于创建搜索引擎): 从Office文档提取图像: 生成包含公式的Excel工作表.  一.NPOI组件概述: NPOI是完全免费使用: 涵盖Exce

  • 详解Next.js页面渲染的优化方案

    在过去一年的工作中我所使用的js框架是Next.js,尽管这个框架在前后端同构方面有着绝佳的体验,但是当页面js文件过大以及preload过多的时候还是会出现页面跳转卡顿和渲染阻塞等比较糟糕的用户体验问题.由于我之前既不知道这个框架的工作原理,自然也就不知道如何去优化它.乘着农历春节前工地活少所以稍微研究一下. 第一个问题:宣称前后台同构的Next.js为何会出现卡顿现象? Next.js 中的特有生命周期hook 函数 getInitialProps会在页面渲染的时候判断浏览器是否为首次渲染,

随机推荐