Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

the-yex/gofmt

Repository files navigation

gofmt 自动字节对齐工具

用于替换 golang源码包中 gofmt 格式化的工具,可以实现自动对代码中struct进行字节对齐的功能。通过增加这一功能,可以使代码更加整洁、易读,提高代码质量和可维护性,并且通过字节对齐,达到节约内存的极致体验

  • 仓库地址 gofmt)
  • gofmt 懂的都懂,本工具拥有与gofmt一模一样的功能,还增加了字节对齐格式化的能力,使用 -a 控制

为什么需要内存对齐

CPU 访问内存时,并不是逐个字节访问,而是以字长(word size)为单位访问。比如 32 位的 CPU ,字长为 4 字节,那么 CPU 访问内存的单位也是 4 字节。 这么设计的目的,是减少 CPU 访问内存的次数,提升 CPU 访问内存的吞吐量。比如同样读取 8 个字节的数据,一次读取 4 个字节那么只需要读取 2 次。

CPU 始终以字长访问内存,如果不进行内存对齐,很可能增加 CPU 访问内存的次数,例如:

img.png 变量 a、b 各占据 3 字节的空间,内存对齐后,a、b 占据 4 字节空间,CPU 读取 b 变量的值只需要进行一次内存访问。 如果不进行内存对齐,CPU 读取 b 变量的值需要进行 2 次内存访问。第一次访问得到 b 变量的第 1 个字节,第二次访问得到 b 变量的后两个字节。

从这个例子中也可以看到,内存对齐对实现变量的原子性操作也是有好处的,每次内存访问是原子的,如果变量的大小不超过字长,那么内存对齐后, 对该变量的访问就是原子的,这个特性在并发场景下至关重要。

内存对齐可以提高内存读写性能,并且便于实现原子性操作。

内存对齐规则

类型 大小
bool 1个字节
intN,uintN,floatN,comlexN N/8个字节(例如 float64是8个字节)
int,uint,uintptr 1个字
*T 1个字
string 2个字(数据、长度)
[]T 3个字(数据、长度、内容)
map 1个字
func 1个字
chan 1个字
interface 2个字(类型)

字长跟CPU相关,32位CPU一个字长就是4字节,64位CPU一个字长是8字节

示例

字节对齐之前的struct混乱无序(瞎JB写的,不要管命名了)

type People struct {
 has bool //1
 Where []int //24
 MachineTime time.Time // 24
 Name string // 16
 donot interface{} //16
 name string //16
 Age int // 8
 inte uintptr //8
 Loves []int // 24
 d []int //24
 sign chan struct{} //8
 age int // 8
 a int8 //1
 c struct {
 a string
		c map[string]int
 b int32 // } haa struct {
 } // 8+8+4 =20
 e []int //24
 b struct{} // 0
}
func main() {
 fmt.Println("before sort", unsafe.Sizeof(People{})) // 256
}

使用gofmt 进行格式化

gofmt -a -w file.go

按字节从大到小进行排序 ,空 struct 比较特殊,不占空间,放第一个最好

type People struct {
	b struct{} // 0
	c struct {
		a string
		c map[string]int
		b int32 // } haa struct {
	} // 8+8+4 =20
	Loves []int // 24
	MachineTime time.Time // 24
	d []int //24
	Where []int //24
	e []int //24
	Name string // 16
	donot interface{} //16
	name string //16
	Age int // 8
	age int // 8
	inte uintptr //8
	sign chan struct{} //8
	has bool //1
	a int8 //1
}
// 排序后一个对象占用少了16个字节
func main() {
 fmt.Println("after sort", unsafe.Sizeof(People{})) // 240
}

注意事项

  • 本工具仅支持 Golang 代码的字节对齐。
  • go version >=1.18
  • 对于对象引用类型不参与排序,置于底部,因为涉及到跨文件访问,这里没有对对象引用进行处理,可以个人略微计算一下进行调整

贡献

如果您对本工具有任何建议或改进意见,欢迎提交 issue 或 pull request。

许可证

MIT License

感谢您使用工具!祝您编程愉快!

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /