Download - Go memory
![Page 1: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/1.jpg)
www.cloudflare.com!
Understanding Go Memory September 11, 2013
John Graham-Cumming
![Page 2: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/2.jpg)
www.cloudflare.com!
Allocation Primitives • new(T)!
• Allocates memory for item with type T!• Zeroes it��
!• make(T)!
• Allocates memory for item with type T!• Initializes it • Needed for channels, maps and slices
• Memory comes from internal heap
ret = runtime·mallocgc(typ->size, flag, 1, 1);!
zeroed
![Page 3: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/3.jpg)
www.cloudflare.com!
Two memory freeing processes • Garbage collection
• Determines which blocks of memory are no longer used • Marks areas of heap so they can be reused by your program
• Scavenging • Determines when parts of the heap are idle for a long time • Returns memory to the operation system
![Page 4: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/4.jpg)
www.cloudflare.com!
Garbage collection • Controlled by the GOGC environment variable
• And by debug.SetGCPercentage()!
• Default is same as GOGC=100!• Can set GOGC=off or debug.SetGCPercentage(-1) (no
garbage collection at all)
// Initialized from $GOGC. GOGC=off means no gc.!//!// Next gc is after we've allocated an extra amount of!// memory proportional to the amount already in use.!// If gcpercent=100 and we're using 4M, we'll gc again!// when we get to 8M. This keeps the gc cost in linear!// proportion to the allocation cost. Adjusting gcpercent!// just changes the linear constant (and also the amount of!// extra memory used).!
![Page 5: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/5.jpg)
www.cloudflare.com!
Scavenging • Runs once per minute
• Can also force return of all unused memory by calling debug.FreeOSMemory()!
// If we go two minutes without a garbage collection, !// force one to run.!forcegc = 2*60*1e9;!!// If a span goes unused for 5 minutes after a garbage!// collection, we hand it back to the operating system.!limit = 5*60*1e9;!
![Page 6: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/6.jpg)
www.cloudflare.com!
Memory Statistics • Read with runtime.ReadMemStats(&m) !
• The MemStats struct has tons of members • Useful ones for looking at heap
• HeapInuse - # bytes in the heap allocated to things • HeapIdle - # bytes in heap waiting to be used • HeapSys - # bytes obtained from OS • HeapReleased - # bytes released to OS
![Page 7: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/7.jpg)
www.cloudflare.com!
Test garbage making program func makeBuffer() []byte { ! return make([]byte, rand.Intn(5000000)+5000000) !}!!func main() { ! pool := make([][]byte, 20)!! makes := 0 ! for { ! b := makeBuffer() makes += 1!! i := rand.Intn(len(pool))! pool[i] = b!! time.Sleep(time.Second)! }!}!
![Page 8: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/8.jpg)
www.cloudflare.com!
What happens
![Page 9: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/9.jpg)
www.cloudflare.com!
debug.FreeOSMemory()!
![Page 10: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/10.jpg)
www.cloudflare.com!
Use a buffered channel func main() {! pool := make([][]byte, 20)! idle:= make(chan []byte, 5)!! makes := 0! for {! var b []byte! select {! case b = <-idle:! default:! makes += 1! b = makeBuffer()! }!! !
i := rand.Intn(len(pool))! if pool[i] != nil {! select {! case idle<- pool[i]:! pool[i] = nil! default:! }! }!! pool[i] = b!! time.Sleep(time.Second)! }!}
![Page 11: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/11.jpg)
www.cloudflare.com!
select for non-blocking receive
idle:= make(chan []byte, 5)!!select {!case b = <-idle: !default:! makes += 1! b = makeBuffer()!}!
Try to get from the idle queue
Idle queue empty? Make a
new buffer
A buffered channel makes a
simple queue
![Page 12: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/12.jpg)
www.cloudflare.com!
select for non-blocking send
idle:= make(chan []byte, 5)!!select {!case buffer <- pool[i]:! pool[i] = nil!!default:!}!
A buffered channel makes a
simple queue
Try to return buffer to the idle queue
Idle queue full? GC will have to deal with the
buffer
![Page 13: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/13.jpg)
www.cloudflare.com!
What happens
![Page 14: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/14.jpg)
www.cloudflare.com!
More realistic: 20 goroutines func main() {! pool := make([][]byte, 200)!! for i := 0; i < 10; i++ {! go func(offset int) {! for {! b := makeBuffer()! j := offset+rand.Intn(20)! pool[j] = b!! time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))! }! }(i*20)! }!}!
![Page 15: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/15.jpg)
www.cloudflare.com!
What happens
![Page 16: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/16.jpg)
www.cloudflare.com!
Shared across goroutines func main() {! buffer := make(chan []byte, 5)!! pool := make([][]byte, 200)! for i := 0; i < 10; i++ {! go func(offset int) {! for {! var b []byte! select {! case b = <-buffer:! default: b = makeBuffer()! }! j := offset+rand.Intn(20)! if pool[j] != nil {! select {! case buffer <- pool[j]: pool[j] = nil! default:! }! }! pool[j] = b! time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))! }! }(i*20)! }!!
![Page 17: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/17.jpg)
www.cloudflare.com!
What Happens
![Page 18: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/18.jpg)
www.cloudflare.com!
More realistic example • Alter code to
• Always try to give back a random buffer from the pool • 50% of the time get a new one
• Should create more garbage
![Page 19: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/19.jpg)
www.cloudflare.com!
Idle length 5
![Page 20: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/20.jpg)
www.cloudflare.com!
Idle length 20
![Page 21: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/21.jpg)
www.cloudflare.com!
Idle length 50
![Page 22: Go memory](https://reader034.vdocuments.us/reader034/viewer/2022051110/54b77a634a795938168b45d0/html5/thumbnails/22.jpg)
www.cloudflare.com!
Also • This works for things other than []byte
• Can be done with arbitrary types • Just need some way to reset
• There’s a proposal to add something like this to the Go package library • sync.Cache • Follow TODO