在Go 1.3.1中获取变量的内存使用情况

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

Get variable memory usage in Go 1.3.1

问题

为什么这段代码无法找到内存使用量(m2-m1)和(m4-m3)的值?
为什么(m3-m2)和(m5-m4)需要分配额外的内存?

代码中的问题可能是由于以下原因导致的:

  1. 在调用runtime.ReadMemStats函数之前,没有将m1m3的值初始化为零。这可能导致输出的初始值为零。
  2. 在调用memUsage函数之前,没有将m2m4的值初始化为零。这可能导致输出的初始值为零。
  3. 在调用memUsage函数时,使用了错误的参数。应该使用&m2&m3,而不是&m2&m3

此外,关于为什么(m3-m2)和(m5-m4)需要分配额外的内存,可能是因为在创建t2t3变量时,分配了新的内存空间来存储字符串和映射。这可能导致内存使用量的增加。

请注意,以上只是对代码中可能存在的问题的猜测,具体原因还需要进一步的调试和分析。

英文:
  1. Why this code can not found the memory usage (m2-m1) and (m4-m3)?
  2. Why (m3-m2) and (m5-m4) require to allocate extra memory?

Full code here

type T struct {
	B uint8
	S string
	I int
}

func memUsage(mOld, mNew *runtime.MemStats) {
	fmt.Println("Alloc:", mNew.Alloc-mOld.Alloc,
		"HeapAlloc:", mNew.HeapAlloc-mOld.HeapAlloc,
		"TotalAlloc:", mNew.TotalAlloc-mOld.TotalAlloc)
}
func main() {
	var m1, m2, m3, m4, m5, m6 runtime.MemStats
	runtime.ReadMemStats(&m1)
	t := T{}
	runtime.ReadMemStats(&m2)
	fmt.Println(t)
	memUsage(&m1, &m2)

	runtime.ReadMemStats(&m3)
	t2 := "abc"
	runtime.ReadMemStats(&m4)
	fmt.Println(t2)
	memUsage(&m3, &m4)

	runtime.ReadMemStats(&m5)
	t3 := map[int]string{1: "x"}
	runtime.ReadMemStats(&m6)
	fmt.Println(t3)
	memUsage(&m5, &m6)

	memUsage(&m2, &m3)
	memUsage(&m4, &m5)
}

Output

{0  0}
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
abc
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
map[1:x]
Alloc: 256 HeapAlloc: 256 TotalAlloc: 256
Alloc: 432 HeapAlloc: 432 TotalAlloc: 432
Alloc: 64 HeapAlloc: 64 TotalAlloc: 64

答案1

得分: 3

变量t在堆栈上分配。

package main

import (
	"fmt"
)

type T struct {
	B uint8
	S string
	I int
}

func main() {
	t := T{}
	fmt.Println(t)
}

伪汇编代码:

0x0021 00033 (t.go:14)	LEAQ	"".statictmp_0002+0(SB),BX
0x0028 00040 (t.go:14)	LEAQ	"".t+88(SP),BP
0x002d 00045 (t.go:14)	MOVQ	BP,DI
0x0030 00048 (t.go:14)	MOVQ	BX,SI
0x0033 00051 (t.go:14)	DUFFCOPY	,$

参考资料:

Plan 9汇编语言手册


你已经大幅修改了你的问题。下次请提一个新问题。

你通过调用fmt包使问题变得复杂。我们只能看到fmt包进行了一些堆分配。我们需要追踪fmt包中的数百行代码才能了解发生了什么。而且,结果是不可重现的。

我移除了所有的杂乱代码:

package main

import (
	"fmt"
	"runtime"
)

type T struct {
	B uint8
	S string
	I int
}

func memUsage(mOld, mNew *runtime.MemStats) {
	fmt.Println("Alloc:", mNew.Alloc-mOld.Alloc,
		"HeapAlloc:", mNew.HeapAlloc-mOld.HeapAlloc,
		"TotalAlloc:", mNew.TotalAlloc-mOld.TotalAlloc)
}
func main() {
	var m1, m2, m3, m4, m5, m6, m7 runtime.MemStats
	runtime.ReadMemStats(&m1)
	t := T{}
	runtime.ReadMemStats(&m2)
	_ = t
	runtime.ReadMemStats(&m3)
	t2 := "abc"
	runtime.ReadMemStats(&m4)
	_ = t2
	runtime.ReadMemStats(&m5)
	t3 := map[int]string{1: "x"}
	runtime.ReadMemStats(&m6)
	_ = t3
	runtime.ReadMemStats(&m7)

	memUsage(&m1, &m2)
	memUsage(&m2, &m3)
	memUsage(&m3, &m4)
	memUsage(&m4, &m5)
	memUsage(&m5, &m6)
	memUsage(&m6, &m7)
}

输出:

Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
Alloc: 256 HeapAlloc: 256 TotalAlloc: 256
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0

很容易看出,除了创建使用堆栈和堆的映射之外,堆栈被使用。

注意:Go的内存管理是依赖于具体实现的。它经常得到改进,即将完全重写。

英文:

Variable t is allocated on the stack.

package main

import (
	"fmt"
)

type T struct {
	B uint8
	S string
	I int
}

func main() {
	t := T{}
	fmt.Println(t)
}

Pseudo-assembler:

0x0021 00033 (t.go:14)	LEAQ	"".statictmp_0002+0(SB),BX
0x0028 00040 (t.go:14)	LEAQ	"".t+88(SP),BP
0x002d 00045 (t.go:14)	MOVQ	BP,DI
0x0030 00048 (t.go:14)	MOVQ	BX,SI
0x0033 00051 (t.go:14)	DUFFCOPY	,$

References:

A Manual for the Plan 9 assembler


You have revised your question substantially. Next time, ask a new question.

You muddy the waters by your calls to the fmt package. All we can see is that the fmt package does some heap allocations. We would have to trace through hundreds of lines of code in the fmt package to see what is happening. Also, the results are not reproducible.

I removed all the clutter:

package main

import (
	"fmt"
	"runtime"
)

type T struct {
	B uint8
	S string
	I int
}

func memUsage(mOld, mNew *runtime.MemStats) {
	fmt.Println("Alloc:", mNew.Alloc-mOld.Alloc,
		"HeapAlloc:", mNew.HeapAlloc-mOld.HeapAlloc,
		"TotalAlloc:", mNew.TotalAlloc-mOld.TotalAlloc)
}
func main() {
	var m1, m2, m3, m4, m5, m6, m7 runtime.MemStats
	runtime.ReadMemStats(&m1)
	t := T{}
	runtime.ReadMemStats(&m2)
	_ = t
	runtime.ReadMemStats(&m3)
	t2 := "abc"
	runtime.ReadMemStats(&m4)
	_ = t2
	runtime.ReadMemStats(&m5)
	t3 := map[int]string{1: "x"}
	runtime.ReadMemStats(&m6)
	_ = t3
	runtime.ReadMemStats(&m7)

	memUsage(&m1, &m2)
	memUsage(&m2, &m3)
	memUsage(&m3, &m4)
	memUsage(&m4, &m5)
	memUsage(&m5, &m6)
	memUsage(&m6, &m7)
}

Output:

Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0
Alloc: 256 HeapAlloc: 256 TotalAlloc: 256
Alloc: 0 HeapAlloc: 0 TotalAlloc: 0

It's easy to see that the stack is used except for creating the map which uses the stack and the heap.

Note: Go memory management is implementation dependent. It's frequently improved and it's about to be completely rewritten.

huangapple
  • 本文由 发表于 2014年9月8日 09:12:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/25716222.html
匿名

发表评论

匿名网友

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

确定