ITPub博客

首页 > 数据库 > Oracle > Go中由WaitGroup引发对内存对齐思考

Go中由WaitGroup引发对内存对齐思考

原创 Oracle 作者:带小饼干给你 时间:2021-01-29 18:10:39 0 删除 编辑

WaitGroup使用大家都会,但是其中是怎么实现的我们也需要知道,这样才能在项目中尽可能的避免由于不正确的使用引发的panic。并且本文也将写一下内存对齐方面做一个解析,喜欢大家喜欢。

WaitGroup介绍

WaitGroup 提供了三个方法:

    func (wg *WaitGroup) Add(delta int)

    func (wg *WaitGroup) Done()

    func (wg *WaitGroup) Wait()

 

Add,用来设置 WaitGroup 的计数值;

Done,用来将 WaitGroup 的计数值减 1,其实就是调用了 Add(-1);

Wait,调用这个方法的 goroutine 会一直阻塞,直到 WaitGroup 的计数值变为 0。

例子我就不举了,网上是很多的,下面我们直接进入正题。

解析

type noCopy struct{}

type WaitGroup struct {

    // 避免复制使用的一个技巧,可以告诉vet工具违反了复制使用的规则

noCopy noCopy

// 一个复合值,用来表示waiter数、计数值、信号量

state1 [3]uint32

}// 获取state的地址和信号量的地址func (wg *WaitGroup) state() (statep *uint64, semap *uint32) {

if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {

// 如果地址是64bit对齐的,数组前两个元素做state,后一个元素做信号量

return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2]

} else {

// 如果地址是 友链交易 32bit对齐的,数组后两个元素用来做state,它可以用来做64bit的原子操作,第一个元素32bit用来做信号量

return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0]

}

}

 

这里刚开始,WaitGroup就秀了一把肌肉,让我们看看大牛是怎么写代码的,思考一个原子操作在不同架构平台上是怎么操作的,在看state方法里面为什么要这么做之前,我们先来看看内存对齐。

内存对齐


A memory address a is said to be n-byte aligned when a is a multiple of n (where n is a power of 2).

简而言之,现在的CPU访问内存的时候是一次性访问多个bytes,比如32位架构一次访问4bytes,该处理器只能从地址为4的倍数的内存开始读取数据,所以要求数据在存放的时候首地址的值是4的倍数存放,者就是所谓的内存对齐。

由于找不到Go语言的对齐规则,我对照了一下C语言的内存对齐的规则,可以和Go语言匹配的上,所以先参照下面的规则。

内存对齐遵循下面三个原则:

结构体变量的起始地址能够被其最宽的成员大小整除;

结构体每个成员相对于起始地址的偏移能够被其自身大小整除,如果不能则在前一个成员后面补充字节;

结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节;

通过下面的例子来实操一下内存对齐:

在32位架构中,int8占1byte,int32占4bytes,int16占2bytes。

type A struct {

a int8

b int32

c int16

}

type B struct {

a int8

c int16

b int32

}

func main() {

 

fmt.Printf("arrange fields to reduce size:\n"+

"A align: %d, size: %d\n" ,

unsafe.Alignof(A{}), unsafe.Sizeof(A{}) )

 

fmt.Printf("arrange fields to reduce size:\n"+

"B align: %d, size: %d\n" ,

unsafe.Alignof(B{}), unsafe.Sizeof(B{}) )

}

//output://arrange fields to reduce size://A align: 4, size: 12//arrange fields to reduce size://B align: 4, size: 8

 

下面以在32位的架构中运行为例子:

在32位架构的系统中默认的对齐大小是4bytes。

假设结构体A中a的起始地址为0x0000,能够被最宽的数据成员大小4bytes(int32)整除,所以从0x0000开始存放占用一个字节即0x00000x0001;b是int32,占4bytes,所以要满足条件2,需要在a后面padding3个byte,从0x0004开始;c是int16,占2bytes故从0x0008开始占用两个字节,即0x00080x0009;此时整个结构体占用的空间是0x0000~0x0009占用10个字节,10%4 != 0, 不满足第三个原则,所以需要在后面补充两个字节,即最后内存对齐后占用的空间是0x0000~0x000B,一共12个字节。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69993776/viewspace-2754595/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-01-23

  • 博文量
    12
  • 访问量
    6081