fieldalignment -fix

开门见山

我们首先来看一段代码

package main

import (
	"fmt"
	"unsafe"
)

type testStruct1 struct {
	testBool1  bool    // 1 byte
	testFloat1 float64 // 8 bytes
	testBool2  bool    // 1 byte
	testFloat2 float64 // 8 bytes
}

type testStruct2 struct {
	testFloat1 float64 // 8 bytes
	testFloat2 float64 // 8 bytes
	testBool2  bool    // 1 byte
	testBool1  bool    // 1 byte

}

func main() {
	a := testStruct1{}
	b := testStruct2{}
	fmt.Println(unsafe.Sizeof(a)) // 32 bytes
	fmt.Println(unsafe.Sizeof(b)) // 24 bytes
}

在64位机器上,我们运行上面的代码后,会发现两个结构相同但字段顺序不同的结构体,它们占用的字节数大小却是不一样的,这就是内存对齐导致的。

内存对齐的基本概念

在Golang中,内存对齐是很重要的一个概念。它是指在内存中分配一个变量时,该变量的地址需要与它的数据类型对齐。也就是说,如果一个变量的数据类型是4字节,那么它的地址必须是4的倍数,否则就需要进行内存对齐。

内存对齐的主要目的是为了提高内存访问的效率。当一个变量的地址与它的数据类型对齐时,CPU可以一次性读取或写入整个变量的值,而不需要进行额外的操作。这可以提高程序的性能。

fieldalignment -fix
fieldalignment-fix
fieldalignment -fix
// 安装fieldalignment命令

go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest

安装完成后,我们可以使用以下命令对我们的代码进行检查:

go vet -vettool=$(which fieldalignment) ./...

这个命令会检查我们的代码中是否存在字段没有正确对齐的情况。如果存在,它会给出相应的警告信息。

不过,我们不能只是检查问题,我们还需要解决问题。我们可以使用以下命令来对我们的代码进行修复:

Tips:执行下面的命令之前先备份下你的代码。

// 修复指定的包(推荐)
fieldalignment -fix 你的包名
// 修复整个项目
fieldalignment -fix ./...
fieldalignment -fixstruct

同时我们会看到类似以下输出:

struct of size 384 could be 376
struct with 296 pointer bytes could be 264
struct with 104 pointer bytes could be 88
struct with 56 pointer bytes could be 32
struct with 80 pointer bytes could be 56
struct of size 224 could be 216
struct with 80 pointer bytes could be 56
struct with 96 pointer bytes could be 72
struct with 176 pointer bytes could be 128
struct with 88 pointer bytes could be 72
struct with 184 pointer bytes could be 168
struct with 48 pointer bytes could be 40
struct with 136 pointer bytes could be 112
struct of size 240 could be 232
struct with 192 pointer bytes could be 144
struct with 80 pointer bytes could be 56
struct with 192 pointer bytes could be 144
struct with 176 pointer bytes could be 144
struct with 24 pointer bytes could be 8
// more...

fieldalignment -fix

注意事项:

fieldalignment -fixfieldalignment -fixstruct

内存对齐的规则

Golang中的内存对齐规则如下:

  1. 基本类型的对齐规则:bool、int8、uint8、byte、rune、int16、uint16、int32、uint32、float32、int64、uint64、float64、complex64、complex128的对齐规则都是它们本身的大小。

  2. 结构体的对齐规则:结构体的对齐规则是结构体中最大字段的大小。也就是说,结构体中的每个字段都要按照它自己的对齐规则进行对齐,然后整个结构体按照最大字段的大小进行对齐。

  3. 数组的对齐规则:数组的对齐规则是数组中元素的对齐规则。也就是说,数组中的每个元素都要按照它自己的对齐规则进行对齐,然后整个数组按照元素的大小进行对齐。

内存对齐的最佳实践

在Golang中,内存对齐的最佳实践如下:

  1. 尽量使用基本类型:基本类型的对齐规则比较简单,不容易出错,而且效率比较高。

  2. 结构体的字段按照大小排列:结构体中的字段应该按照它们的大小从大到小进行排列,这样可以避免因为对齐而浪费内存。

  3. 结构体的大小应该是2的幂次方:结构体的大小应该尽量是2的幂次方,这样可以避免因为对齐而浪费内存。

  4. 使用数组而不是切片:数组的对齐规则比较简单,而且效率比切片高,所以如果不需要动态扩展,应该尽量使用数组。

  5. 避免跨越对齐边界:如果一个结构体的字段跨越了对齐边界,那么这个结构体的对齐规则就会变得比较复杂,容易出错,所以应该尽量避免跨越对齐边界。