RT
go WaitGroup 中有这样的代码:
type WaitGroup struct {
noCopy noCopy
// 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
// 64-bit atomic operations require 64-bit alignment, but 32-bit
// compilers do not ensure it. So we allocate 12 bytes and then use
// the aligned 8 bytes in them as state, and the other 4 as storage
// for the sema.
state1 [3]uint32
}
func (wg *WaitGroup) state() (statep *uint64, semap *uint32) {
if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2]
} else {
return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0]
}
}
这个 uintptr(unsafe.Pointer(&wg.state1))会不会受到 gc 的影响, 比如在 gc 后地址就变了..
变成%8==4 了.. (包括在 32 位对齐的机器上是否有地址改变这种问题) ??
有知道的大佬多说说 🐶
相关知识链接(随便找个): https://www.helloworld.net/p/8378277893
1
BBCCBB OP ```go
type Wg struct { state1 [3]uint32 } func main() { var wg Wg fmt.Println(uintptr(unsafe.Pointer(&wg.state1)) % 8) } ``` 64 位 mac 上执行这个代码多次, 是会出现 0 和 4 两种结果的 |
2
BBCCBB OP 64 位对齐不是说数据的地址是 8 的整数倍吗... 那为啥这里还有 0 和 4 两种结果?
|
5
Huelse 2021-09-28 10:21:07 +08:00
the garbage collector will not update that uintptr's value if the object moves, nor will that uintptr keep the object from being reclaimed.
https://pkg.go.dev/unsafe#Pointer |
6
katsusan 2021-09-28 11:34:56 +08:00
> 64 位对齐不是说数据的地址是 8 的整数倍吗... 那为啥这里还有 0 和 4 两种结果?
1 楼例子里的 Wg 是 4 字节对齐的,unsafe.Alignof(wg)或 reflect.TypeOf(wg).Align()可以看到。 > 64 位 mac 上执行这个代码多次, 是会出现 0 和 4 两种结果的 wg 分配在栈上,受 runtime 申请栈空间时获得的地址影响,不一定保证 8 字节对齐还是只满足 4 字节对齐。 > 加一个 fmt.Println(wg)使其在堆上分配 加 fmt.Println 让 wg 分配在堆上利用了 tiny allocator 获得的 tiny block 地址在 64 位环境下为 8 字节对齐, 不代表内存分配器一定会给 wg 返回 8 字节对齐的地址,比如下面的代码里 wg 的地址应该只满足 4 字节对齐。 ```Go type Wg struct { state1 [3]uint32 } func main() { var b bool var wg Wg fmt.Printf("%p\n", &b) fmt.Printf("%p\n", &wg) } ``` |
7
cholerae 2021-09-28 13:23:01 +08:00
"gc 后地址就变了" 是啥意思? go 没有移动 gc
|
9
BBCCBB OP @katsusan
> 64 位对齐不是说数据的地址是 8 的整数倍吗... 那为啥这里还有 0 和 4 两种结果? 这个看下来只要地址是 unsafe.AlignOf(wg)的 整数倍就行了? 64 位机器上没要求对象地址必须是 8 的整数倍? gc 对象位置在内存里被移动 这个问题大佬知道吗? |
10
katsusan 2021-09-28 16:17:31 +08:00
@BBCCBB #9
> 64 位机器上没要求对象地址必须是 8 的整数倍? 除了一些特别的操作比如 atomic 外,没有强制。但地址对齐对访问内存性能有影响,非对齐地址会导致需要拆分成两次内存访问。在 amd64 下,对于 byte 型数据需要 1 字节对齐,word 需要 2 字节,doubleword 需要 4 字节,quadword 需要 8 字节对齐。 > gc 对象位置在内存里被移动 我看了下 JAVA 的各式 GC 算法里普遍对 young generation 使用 mark-copy 算法,对 old generation 使用 mark-sweep 算法。 你说的移动指的是 copy 过程中的移动吧,Golang 里未采用分代 GC,只有 mark-sweep 。 |
11
BBCCBB OP @katsusan jvm 老年代里的 gc 有 mark-sweep, 也有 mark-sweep & compact, 压缩, 防止内存碎片用的,
go 里只有标记清除, 没有整理内存, 压缩这个操作是不? |
13
BBCCBB OP @katsusan 简单看了下 go 的 gc, 没有 compact 操作, 内存都被 tmolloc 这种分配器切成一块一块的..
|
14
BBCCBB OP @katsusan 我还看到一个概念
The first word in a variable or in an allocated struct, array, or slice can be relied upon to be 64-bit aligned. 变量或开辟的结构体、数组和切片值中的第一个 64 位字可以被认为是 8 字节对齐 这一句中开辟的意思是通过声明,make,new 方式创建的,就是说这样创建的 64 位字可以保证是 64 位对齐的。 |
15
BBCCBB OP 地址按照这个规则来对齐
uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0 |
16
my3157 2021-09-29 04:58:35 +08:00 via Android
|