首页 > 解决方案 > 将新结构重新分配给变量时,golang会分配新内存吗?

问题描述

当我将新的结构对象重新分配给现有变量时,地址不会改变。代码如下所示:

type Request struct {
    Field string
}
func main(){
    r := Request{Field: "a"}
    fmt.Printf("%p\n", &r)
    r = Request{Field: "b"}
    fmt.Printf("%p\n", &r)
}

输出:

0xc0004040d0
0xc0004040d0

这就像在Feild没有分配新内存的情况下进行了修改。那么当重新分配发生时,Go 会做什么呢?

如果我想使用sync.pool,我可以像重置一样将obj放入池中r := Request{}吗?(我的意思是通过这个操作,struct obj 可以被重用,并且不会被 . 收集gc。)

标签: gomemorystructpoolcomposite-literals

解决方案


规范:复合文字仅声明当您获取复合文字的地址时,它将指向一个未命名的变量,因此需要分配:

获取复合文字的地址会生成一个指针,该指针指向使用该文字的值初始化的唯一变量。

当您不获取文字的地址时,只需分配它,不需要分配,可以将结构值分配给已经分配内存的变量。

为了验证,我们可以使用 Go 的测试框架。创建一个测试文件:

package main

import (
    "testing"
)

type Request struct {
    Field string
}

var r = Request{Field: "a"}

func BenchmarkStruct(b *testing.B) {
    for i := 0; i < b.N; i++ {
        r = Request{Field: "b"}
    }
}

var p = &Request{Field: "a"}

func BenchmarkStructPtr(b *testing.B) {
    for i := 0; i < b.N; i++ {
        p = &Request{Field: "b"}
    }
}

运行它:

go test -bench . -benchmem

输出:

BenchmarkStruct-4       1000000000       0.948 ns/op       0 B/op    0 allocs/op
BenchmarkStructPtr-4    32160099        37.3 ns/op        16 B/op    1 allocs/op

如您所见,Request使用复合文字分配结构的值不需要分配。获取它的地址并分配需要 16 个字节分配(在我的 64 位架构上),这是Request包含单个string类型字段的结构的大小,字符串头是一个指针(8 个字节)和一个长度(8字节)。

在 Go 中赋值总是会产生副本。因此,当您分配任何值(包括结构值)时,该值将被复制,并且您分配给它的变量不会引用原始值。


推荐阅读