Daniel YC Lin
Daniel YC Lin

Reputation: 16002

Get variable memory usage in Go 1.3.1

  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

Upvotes: 1

Views: 190

Answers (1)

peterSO
peterSO

Reputation: 166569

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.

Upvotes: 3

Related Questions