英文:
how a pointer to a struct member keeps the struct alive in Go
问题
给定以下的Go语言代码:
type Pointer struct { x, y int }
func foo(p *Pointer) *int {
return &p.y
}
CompilerExplorer 显示return &p.y编译成了以下汇编代码:
TESTB AL, (AX)
ADDQ $8, AX
RET
很容易理解。TESTB是一个空指针检查,然后ADDQ通过将Pointer::y的偏移量加到p上来生成指向p.y的指针。
我不明白的是,给定一个指向p.y的指针,垃圾回收器如何知道它不仅仅是一个任意的*int,而是一个指向Pointer::y的指针,所以只要指向p.y的指针还活着,p就必须保持存活?
英文:
Given the following golang code:
type Pointer struct { x, y int }
func foo(p *Pointer) *int {
return &p.y
}
CompilerExplorer shows that return &p.y compiles to
TESTB AL, (AX)
ADDQ $8, AX
RET
It's easy to understand. TESTB is a null check, then ADDQ produce a pointer to p.y by adding offset of Pointer::y to p.
What I don't understand is, given a pointer to p.y, how does the garbage collector knows it's not just an arbitrary *int, but a pointer to a Pointer::y, so p must remain alive as long as a pointer to p.y is still alive?
答案1
得分: 3
阅读了源代码后(链接:https://github.com/golang/go/blob/85a482fc244f6f118b1d063063a51eb8b0feadd8/src/runtime/mbitmap.go#L391),我找到了答案。
- Go使用基于arena/span的分配方式。
- Arenas和spans与页面对齐,因此可以轻松计算指针指向的是哪个arena。
- 有一个全局向量存储所有arenas和spans的元数据。
- 每个span都有一个固定的“元素大小”。同一span中的所有对象大小相同。
- 给定指针
p,span的基地址b和span的元素大小s,我们可以知道指针指向span中的第n个元素,其中n = (p - b) / s。 - 因此,span中第n个对象的地址为
b + s * n,需要将其标记为存活。
英文:
After reading the source code I found the answer.
- Go use arena / span based allocation.
- Arenas and spans are aligned with pages, so it's trivial to calculate which arena is the pointer pointing to.
- There's a global vector stores metadata of all arenas and spans.
- Each span has a fixed "element size". All objects in the same span have the same size.
- Given the pointer
p, base address of spanband element size of spans, we know the pointer is pointing n-th element in the span, wheren = (p - b) / s. - So the address of n-th object in the span
b + s * n, which needs to be marked as alive.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论