英文:
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 spanb
and 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论