Go类型的方法集在内存中是如何分配的?

huangapple go评论135阅读模式
英文:

How are Go type method sets allocated in memory?

问题

C++避免在每次创建实例时为类方法分配内存。我直觉上认为Go也会减少这种重复。只是为了确认一下,Go是否只存储自定义结构体的方法集一次?

type Custom struct {
    value string
}

func (c Custom) TurnItUp() {
    c.value = "up"
}

func (c Custom) TurnItDown() {
    c.value = "down"
}

... // 为Custom定义了更多的方法。
    //(在100个维度中的正向和负向)

func main() {
    var many []Custom
    fmt.Println("Memory: ", foo.memory()) // 测量使用的内存。
    for i := 0; i < 10000; i++ {
        many = append(many, Custom{value: "nowhere"})
    } 
    fmt.Println("Memory: ", foo.memory()) // 测量使用的内存。
}
英文:

C++ avoids allocating memory for class methods every time an instance is created. My gut feeling is to assume that Go also mitigates this kind of duplication. Just to confirm, does Go store the method set of a custom struct only once?

type Custom struct {
    value string
}

func (c Custom) TurnItUp() {
    c.value = &quot;up&quot;
}

func (c Custom) TurnItDown() {
    c.value = &quot;down&quot;
}

... // Many more methods defined for Custom. 
    // (Positive and negative directions in 100 dimensions)

func main() {
    var many []Custom
    fmt.Println(&quot;Memory: &quot;, foo.memory()) // Measure memory used.
    for i := 0; i &lt; 10000; i++ {
        append(many, Custom{value: &quot;nowhere&quot;})
    } 
    fmt.Println(&quot;Memory: &quot;, foo.memory()) // Measure memory used. 
}

答案1

得分: 3

运行时在将具体类型分配给接口类型时会分配一个 itable。具体类型和接口类型的 itable 被缓存并在后续的分配中使用。

举个例子,下面的代码将分配一个 itable:

type Volume interface {
    TurnItUp()
    TurnItDown()
}
var many []Volume
for i := 0; i < 10000; i++ {
    many = append(many, Custom{value: "nowhere"})
}

而下面的代码将分配两个 itable,一个是 (Custom, Upper) 的,另一个是 (Custom, Downer) 的:

type Upper interface {
    TurnItUp()
}
type Downer interface {
    TurnItDown()
}
var uppers []Upper
var downers []Downer
for i := 0; i < 10000; i++ {
    uppers = append(uppers, Custom{value: "nowhere"})
    downers = append(downers, Custom{value: "nowhere"})
}

因为问题中的示例没有将 Custom 值分配给接口,所以不会创建 itable。

运行时使用静态元数据来构建 itable。静态数据只会被分配和初始化一次。

详细信息请参考 Go 数据结构:接口

英文:

The runtime allocates an itable when a concrete type is assigned to an interface type. The itable for the concrete type and interface type is cached and used on later assignments.

As an example, this code will allocate one itable:

type Volume interface {
    TurnItUp()
    TurnItDown()
}
var many []Volume
for i := 0; i &lt; 10000; i++ {
    many = append(many, Custom{value: &quot;nowhere&quot;})
}

and this code will allocate two itables, one for (Custom, Upper) and one for (Custom, Downer):

type Upper interface {
    TurnItUp()
}
type Downer interface {
    TurnItDown()
}
var uppers []Upper
var downers []Downer
for i := 0; i &lt; 10000; i++ {
    uppers = append(uppers, Custom{value: &quot;nowhere&quot;})
    downers = append(downers, Custom{value: &quot;nowhere&quot;})
}

Because the example in the question does not assign a Custom value to an interface, no itables are created.

The runtime uses static metadata data to construct itables. The static data is allocated and initialized once.

See Go Data Structures: Interfaces for more details.

答案2

得分: 3

Bravada Zadada基本上回答了你的问题,但是这里是如何创建一个测试来显示某个操作引起了多少次分配的方法:

func TestMethods(t *testing.T) {
    mem := testing.AllocsPerRun(10000000, func() {
        _ = Custom{value: "nowhere"}
    })
    if mem != 0 {
        t.Errorf("创建一个对象分配了 %v 内存", mem)
    }
}

请参阅testing.AllocsPerRun文档。你可以使用类似的测试来测试接口、指针方法等等。

英文:

Bravada Zadada basically answered your question, but here's how you make a test that shows how many allocations does a certain action cause:

func TestMethods(t *testing.T) {
	mem := testing.AllocsPerRun(10000000, func() {
		_ = Custom{value: &quot;nowhere&quot;}
	})
	if mem != 0 {
		t.Errorf(&quot;creating an object allocated %v memory&quot;, mem)
	}
}

See testing.AllocsPerRun documentation. You can make similar tests with interfaces, pointer methods and what not.

huangapple
  • 本文由 发表于 2015年7月14日 11:26:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/31397094.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定