package main
import (
"fmt"
"runtime/debug"
"time"
)
// run with escape analysis
// go run -gcflags '-m -l' main.go
func main() {
a()
fmt.Println("after a returned")
debug.FreeOSMemory()
fmt.Println("after GC")
time.Sleep(5 * 60 * time.Second)
fmt.Println("after 5 minutes")
time.Sleep(10 * 60 * time.Second)
}
func a() {
a := [10485760]byte{} // doesn't escape to the heap
_ = a
fmt.Println("after alocating 10485760 slice")
b := [10485761]byte{} // does escape to the heap
_ = b
fmt.Println("after alocating 10485761 slice")
c := [10000000000]byte{} // does escape to the heap
// to trigger page fault? without this i don't see RSS growing that much
// https://github.com/golang/go/issues/14045
for i := 0; i < len(c); i += 4096 {
c[i] = 'x'
}
_ = c
fmt.Println("after alocating a lot of memory slice")
}$ GODEBUG=gctrace=1 go run -gcflags '-m -l' main.go
# command-line-arguments./main.go:26:22: moved to heap: b./main.go:30:25: moved to heap: c./main.go:25:14: "after alocating 10485760 slice" escapes to heap./main.go:28:14: "after alocating 10485761 slice" escapes to heap./main.go:38:14: "after alocating a lot of memory slice" escapes to heap./main.go:25:13: a ... argument does not escape./main.go:28:13: a ... argument does not escape./main.go:38:13: a ... argument does not escape
...$ vmmap <PID>
VIRTUAL RESIDENT DIRTY SWAPPED VOLATILE NONVOL EMPTY REGION
REGION TYPE SIZE SIZE SIZE SIZE SIZE SIZE SIZE COUNT (non-coalesced)
=========== ======= ======== ===== ======= ======== ====== ===== =======
STACK GUARD 56.0M 0K 0K 0K 0K 0K 0K 2
Stack 8192K 20K 20K 0K 0K 0K 0K 2
VM_ALLOCATE 528.5G 4.9G 30.1M 286.1M 0K 0K 0K 6
__DATA 424K 148K 132K 0K 0K 0K 0K 5
__LINKEDIT 216K 76K 0K 0K 0K 0K 0K 3
__TEXT 1452K 976K 0K 0K 0K 0K 0K 3
shared memory 8K 8K 8K 0K 0K 0K 0K 3
=========== ======= ======== ===== ======= ======== ====== ===== =======
TOTAL 528.6G 4.9G 30.2M 286.1M 0K 0K 0K 17
GODEBUG=gctrace=1 go run -gcflags '-m -l' main.go
gc 1 @0.102s 0%: 0.10+0.19+0.036 ms clock, 0.80+0/0.33/0.40+0.29 ms cpu, 4->4->0 MB, 5 MB goal, 8 P
gc 2 @0.147s 0%: 0.009+0.25+0.027 ms clock, 0.079+0.13/0.33/0.66+0.21 ms cpu, 4->4->0 MB, 5 MB goal, 8 P
# command-line-arguments
./main.go:26:22: moved to heap: b
./main.go:30:25: moved to heap: c
./main.go:25:14: "after alocating 10485760 slice" escapes to heap
./main.go:28:14: "after alocating 10485761 slice" escapes to heap
./main.go:38:14: "after alocating a lot of memory slice" escapes to heap
./main.go:25:13: a ... argument does not escape
./main.go:28:13: a ... argument does not escape
./main.go:38:13: a ... argument does not escape
./main.go:14:14: "after a returned" escapes to heap
./main.go:16:14: "after GC" escapes to heap
./main.go:18:14: "after 5 minutes" escapes to heap
./main.go:14:13: main ... argument does not escape
./main.go:16:13: main ... argument does not escape
./main.go:18:13: main ... argument does not escape
gc 1 @0.007s 0%: 0.059+1.5+0.033 ms clock, 0.47+1.1/1.8/2.5+0.27 ms cpu, 4->4->3 MB, 5 MB goal, 8 P
# command-line-arguments
gc 1 @0.000s 0%: 0.072+2.7+0.030 ms clock, 0.58+0.17/2.6/0.19+0.24 ms cpu, 4->5->4 MB, 5 MB goal, 8 P
gc 2 @0.008s 0%: 0.056+1.3+0.041 ms clock, 0.45+0.11/1.9/1.5+0.33 ms cpu, 7->8->7 MB, 9 MB goal, 8 P
gc 3 @0.025s 0%: 0.008+2.6+0.079 ms clock, 0.067+0.068/4.0/1.7+0.63 ms cpu, 13->14->13 MB, 15 MB goal, 8 P
gc 4 @0.073s 0%: 0.013+5.6+0.040 ms clock, 0.10+0.17/10/0.34+0.32 ms cpu, 23->24->22 MB, 26 MB goal, 8 P
after alocating 10485760 slice
after alocating 10485761 slice
gc 1 @0.012s 0%: 0.086+0.10+0.035 ms clock, 0.69+0.053/0.016/0.099+0.28 ms cpu, 10->10->0 MB, 11 MB goal, 8 P
after alocating a lot of memory slice
after a returned
gc 2 @0.194s 0%: 0.043+6646+0.16 ms clock, 0.34+0/0.17/6646+1.3 ms cpu, 9536->9536->0 MB, 9537 MB goal, 8 P (forced)
gc 3 @6.841s 0%: 0.013+0.67+0.032 ms clock, 0.10+0/0.68/0.30+0.26 ms cpu, 0->0->0 MB, 8 MB goal, 8 P (forced)
scvg-1: 9561 MB released
scvg-1: inuse: 0, idle: 9561, sys: 9561, released: 9561, consumed: 0 (MB)
after GC
GC forced