为了账号安全,请及时绑定邮箱和手机立即绑定

Go 内存分配 - 新对象、指针和转义分析

Go 内存分配 - 新对象、指针和转义分析

Go
慕尼黑8549860 2022-09-05 15:31:26
我读到Golang语言以一种聪明的方式管理内存。使用转义分析,go 在调用 new 时可能不会分配内存,反之亦然。golang可以用这样的符号分配内存吗 ?或者指针始终指向堆栈var bob * Person = & Person {2, 3}
查看完整描述

3 回答

?
慕妹3146593

TA贡献1820条经验 获得超9个赞

指针可能会转义到堆中,也可能不转义,具体取决于您的使用案例。编译器非常智能。例如,给定:


type Person struct {

    b, c int

}



func foo(b, c int) int {

    bob := &Person{b, c}

    return bob.b

}

该函数将编译为:foo


    TEXT    "".foo(SB)

    MOVQ    "".b+8(SP), AX

    MOVQ    AX, "".~r2+24(SP)

    RET

它全部位于此处的堆栈上,因为即使它是指针,它也不会逃脱此函数的作用域。bob


但是,如果我们考虑轻微的(尽管是人为的)修改:


var globalBob *Person


func foo(b, c int) int {

    bob := &Person{b, c}

    globalBob = bob

    return bob.b

}

然后转义,并将编译为:bobfoo


    TEXT    "".foo(SB), ABIInternal, $24-24

    MOVQ    (TLS), CX

    CMPQ    SP, 16(CX)

    PCDATA  $0, $-2

    JLS     foo_pc115

    PCDATA  $0, $-1

    SUBQ    $24, SP

    MOVQ    BP, 16(SP)

    LEAQ    16(SP), BP

    LEAQ    type."".Person(SB), AX

    MOVQ    AX, (SP)

    PCDATA  $1, $0

    CALL    runtime.newobject(SB)

    MOVQ    8(SP), AX

    MOVQ    "".b+32(SP), CX

    MOVQ    CX, (AX)

    MOVQ    "".c+40(SP), CX

    MOVQ    CX, 8(AX)

    PCDATA  $0, $-2

    CMPL    runtime.writeBarrier(SB), $0

    JNE     foo_pc101

    MOVQ    AX, "".globalBob(SB)

 foo_pc83:

    PCDATA  $0, $-1

    MOVQ    (AX), AX

    MOVQ    AX, "".~r2+48(SP)

    MOVQ    16(SP), BP

    ADDQ    $24, SP

    RET

如您所见,它调用 .newobject


这些反汇编列表由 https://godbolt.org/ 生成,在 amd64 上为 go 1.16 生成


查看完整回答
反对 回复 2022-09-05
?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

是将内存分配给堆栈上还是“转义”到堆中,完全取决于您如何使用内存,而不是如何声明变量。

如果返回指向堆栈分配变量的指针(例如 C),则当您尝试使用它时,指针的值将无效。这在 Go 中是不可能的,因为您无法显式告诉 Go 将变量放置在何处。它在选择正确的位置方面做得很好,如果它看到对内存 blob 的引用可能位于堆栈帧之外,它将确保在堆上进行分配。

golang可以用这样的符号分配内存吗?

var bob * Person = & Person {2, 3}

或者指针始终指向堆栈

不能说这行代码“总是”指向堆栈,但它有时可能会,所以是的,它可能会分配内存(在堆上)。

同样,这不是关于那行代码,而是关于它之后会发生什么。如果返回值 (对象的地址),则无法在堆栈上分配它,因为返回的地址将指向回收的内存。bobPerson


查看完整回答
反对 回复 2022-09-05
?
守着一只汪

TA贡献1872条经验 获得超3个赞

简而言之,如果编译器可以证明该值可以在堆栈上安全地创建,那么它将(可能)在堆栈上创建。否则,它将在堆上分配。

编译器必须执行这些证明的工具非常好,但它并不总是正确。然而,大多数时候,担心它的成本与收益并没有真正的好处。


查看完整回答
反对 回复 2022-09-05
  • 3 回答
  • 0 关注
  • 103 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信