type MySt struct {
a uint8
b uint64
c uint64
}
func main() {
var my MySt
fmt.Println(unsafe.Sizeof(my))
atomic.AddUint64(&my.b, 1)
}
上述在64位操作系统上工作正常,并且打印24
.
当我们设置编译参数编译32位程序
SET GOARCH=386
go build
再次运行该程序就会发生Painc
20
sync/atomic.AddUint64(0x10d7a004, 0x1, 0x0, 0x10d2e280, 0x10d78030)
D:/go1.10.windows-amd64/go/src/sync/atomic/asm_386.s:112 +0xc
main.main()
D:/go1.10.windows-amd64/gopath/src/git.hzauth.com/gmsslvpn/unisign-tlcp-pxy/proxy/test/main.go:14 +0x50
32位系统下,变量最大存储也就是uint32
也就是4个字节
32位程序,由于内存分配机制每个分配内存的单元是4个字节,在分配 MySt
的第一个参数a
时只使用了1个字节,但是b
需要8个字节,此时内存布局为
| a | - | - | - | - |
| b | b | b | b | b |
| b | b | b | b | b |
| c | c | c | c | c |
| c | c | c | c | c |
当我们在程序中使用uint64
时,如果没有对该变量的内存对其那么就会导致GO原子指令panic
解决
调整结构体的内存布局,进行 内存对齐
type MySt struct {
b uint64
c uint64
a uint8
}
参考文献
[1]. 开发者头条 . Go 夜读 . Go 在 32 位系统中使用 64 位原子操作的坑 . https://toutiao.io/posts/jagmqm/preview
[2]. golang . https://golang.google.cn/pkg/sync/atomic/#pkg-note-BUG