Slide 1

Slide 1 text

Entendendo alocação de memória no Go André Carvalho @andresantostc 1

Slide 2

Slide 2 text

Desenvolvedor @ Globo.com tsuru.io https://andrestc.com 2

Slide 3

Slide 3 text

3

Slide 4

Slide 4 text

Por que? ● Conhecer os trade-offs ● Conhecer uma camada de abstração abaixo ● Porque não? 4

Slide 5

Slide 5 text

func main() { rand.Seed(time.Now().UnixNano()) i := rand.Intn(100) fmt.Printf("%v at %p\n", i, &i) for { } } 5

Slide 6

Slide 6 text

6 $ ./vmemory 53 at 0xc420016110 $ ./vmemory 68 at 0xc420016110 Rodando o programa duas vezes ao mesmo tempo... Mesmo endereço

Slide 7

Slide 7 text

Memória Virtual ● Processos não leem diretamente da memória física ○ Segurança ○ Coordenação entre múltiplos processos ● Memória Virtual abstrai isso dos processos ○ Segmentation ○ Page tables 7

Slide 8

Slide 8 text

Memória Virtual 8 Frame 0 Frame 1 Frame 2 Frame 3 Frame 4 Frame 5 Frame 6 Frame 7 RAM Disk Other process Page 0 Page 1 Page 2 Page 3 Page 4 Page 5 Page 6 Page 7 Page Process Frame Page Table 3 6

Slide 9

Slide 9 text

Layout de um Processo 9 Text Data Heap BSS Stack Program Break Code Initialized static variables Uninitialized static variables Dynamic allocated variables Function stack frames

Slide 10

Slide 10 text

Alocação na Stack 10 Stack Used Stack Pointer (SP) Unused Allocation SP += size; return Stack[SP-size]; Deallocation SP -= size;

Slide 11

Slide 11 text

Alocação na Heap ● Objetos com tamanho conhecido apenas em tempo de execução ● C tem malloc e free ● C++ tem new e delete ● Go usa escape analysis e garbage collection 11

Slide 12

Slide 12 text

Alocador Simples 12

Slide 13

Slide 13 text

Alocador Simples Precisamos implementar duas funções 13 void* malloc(size_t size) void free(void *ptr)

Slide 14

Slide 14 text

Alocador Simples 14 Application Allocator OS malloc mmap Alocador utiliza syscalls como mmap/munmap para falar com o OS munmap madvise free

Slide 15

Slide 15 text

Alocador Simples Lista encadeada de objetos disponíveis size=n next=* Header n bytes size=m next=nil m bytes 15 Head

Slide 16

Slide 16 text

Alocador Simples - Alocação malloc(10) 16 Head NULL

Slide 17

Slide 17 text

Alocador Simples 17 Virtual Address Space 0x000000c000000000 mmap( 0x000000c000000000, 4096, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, ...) Start Address Size Permission Flags

Slide 18

Slide 18 text

Alocador Simples - Alocação malloc(10) 18 4084 12 4084 4096 Head

Slide 19

Slide 19 text

Alocador Simples - Alocação malloc(10) 19 4062 Head 10 22

Slide 20

Slide 20 text

Alocador Simples - Alocação malloc(10) 20 4062 Head 10 P Allocator returns p, which points right after the header

Slide 21

Slide 21 text

21 Alocador Simples - Desalocação 4062 Head free(p) 10

Slide 22

Slide 22 text

free(p) 10 p - size(header) 22 Alocador Simples - Desalocação 4062 Head

Slide 23

Slide 23 text

Alocador Simples ● Pode ser implementado em algumas centenas de LOCs ● Questões não endereçadas ○ Fragmentação ○ Devolver memória para o OS ■ Quando? ■ Como? munmap, madvise... ○ Multi-thread ○ ... 23

Slide 24

Slide 24 text

Go Runtime Allocator 24 ● TCMalloc ● Invocando o Alocador ● Go’s Allocator

Slide 25

Slide 25 text

Thread-Caching Malloc (TCMalloc) ● Implementado originalmente em C pelo Google ● Serve como base para o algoritmo usado pelo Go ● Diminui lock-contention em programas multi-threaded 25

Slide 26

Slide 26 text

TCMalloc ● Cada thread tem um cache local ● Dois tipos de alocação ○ Small allocations (<= 32 kB) ○ Large allocations 26

Slide 27

Slide 27 text

TCMalloc - Small Allocations ● Atendidas pelo cache local da thread ● Tamanho é arredondado para o de uma das classes 27 malloc(965 bytes) ⇒ malloc(1024 bytes) malloc(1023 bytes) ⇒ malloc(1024 bytes)

Slide 28

Slide 28 text

TCMalloc - Small Allocations Class 0 Class 1 Class 2 ... Local Thread Cache 28

Slide 29

Slide 29 text

TCMalloc - Small Allocations Class 0 Class 1 Class 2 ... Local Thread Cache 29

Slide 30

Slide 30 text

TCMalloc - Small Allocations Class 0 Class 1 Class 2 ... Local Thread Cache Span Span Span ... Central Free List Class 1 30 Run of contiguous pages Span

Slide 31

Slide 31 text

TCMalloc - Small Allocations Class 0 Class 1 Class 2 ... Local Thread Cache Span Span Span ... Central Free List Class 1 31

Slide 32

Slide 32 text

TCMalloc - Small Allocations Span Span Span Central Free List Class X Span 1 page 2 pages ... > 255 pages Span Span Span Span Span Span Span Central Heap 32

Slide 33

Slide 33 text

TCMalloc - Small Allocations Span Span Span Central Free List Class X Span 1 page 2 pages ... > 255 pages Span Span Span Span Span Span Central Heap Span ... 33 Span

Slide 34

Slide 34 text

TCMalloc - Small Allocations Application Local Thread Cache Central Free List Central Heap 4 bytes N 8-byte objects X pages OS Y*X pages 34 X pages N 8-byte objects Y*X pages

Slide 35

Slide 35 text

TCMalloc - Large Allocations ● Atendidas pela Heap central ● Tamanho é arredondado para numero de paginas 35 malloc(34 kB) ⇒ malloc(36 kB) ⇒ 9 pages malloc(33 kB) ⇒ malloc(36 kB) ⇒ 9 pages

Slide 36

Slide 36 text

TCMalloc - Large Allocations 1 page 2 pages ... > 255 pages Span Span Span Span Span Span Central Heap Span Span 36

Slide 37

Slide 37 text

TCMalloc - Deallocation Page 1 Page 2 Page 3 Page 4 Page 5 Page 6 Span A Span B Span C 37

Slide 38

Slide 38 text

TCMalloc - Deallocation free( ) Page Span 38

Slide 39

Slide 39 text

TCMalloc - Deallocation free( ) Page Span Class 0 Class 1 Class 2 ... Local Thread Cache Small object 39

Slide 40

Slide 40 text

TCMalloc - Deallocation free( ) Page Span Large object Page 1 Page 2 Page 3 Page 4 Span A Span B Span C 40

Slide 41

Slide 41 text

TCMalloc - Deallocation free( ) Page Span Large object Page 1 Page 2 Page 3 Page 4 Span A Span B 41

Slide 42

Slide 42 text

TCMalloc - Deallocation free( ) Page Span Large object 1 page 2 pages ... > 255 pages Span B Central Heap 42

Slide 43

Slide 43 text

TCMalloc - Deallocation free( ) Page Span Large object 1 page 2 pages ... > 255 pages Span B Central Heap 43

Slide 44

Slide 44 text

Go Runtime Allocator 44 ● TCMalloc ● Invocando o Alocador ● Go’s Allocator

Slide 45

Slide 45 text

package main func main() { f() } //go:noinline func f() *int { i := 10 return &i } 45

Slide 46

Slide 46 text

package main func main() { f() } //go:noinline func f() *int { i := 10 return &i } 46 $ go build -gcflags "-m -m" main.go # command-line-arguments ./main.go:8:6: cannot inline f: marked go:noinline ./main.go:3:6: cannot inline main: non-leaf function ./main.go:10:9: &i escapes to heap ./main.go:10:9: from ~r0 (return) at ./main.go:10:2 ./main.go:9:2: moved to heap: i

Slide 47

Slide 47 text

47 $ go tool compile -S main.go ... 0x001d 00029 (main.go:9) LEAQ type.int(SB), AX 0x0024 00036 (main.go:9) MOVQ AX, (SP) 0x0028 00040 (main.go:9) PCDATA $0, $0 0x0028 00040 (main.go:9) CALL runtime.newobject(SB) ...

Slide 48

Slide 48 text

48 $ go tool compile -S main.go ... 0x001d 00029 (main.go:9) LEAQ type.int(SB), AX 0x0024 00036 (main.go:9) MOVQ AX, (SP) 0x0028 00040 (main.go:9) PCDATA $0, $0 0x0028 00040 (main.go:9) CALL runtime.newobject(SB) ... func newobject(typ *_type) unsafe.Pointer { return mallocgc(typ.size, typ, true) }

Slide 49

Slide 49 text

Go Runtime Allocator 49 ● TCMalloc ● Invoking the Allocator ● Go’s Allocator

Slide 50

Slide 50 text

Go’s Allocator ● Acoplado ao GC e outras partes do runtime ○ Difícil de trocar por outras implementações ● Três tipos de alocação ○ Tiny Allocations (no pointers, size < 16 bytes) ○ Small Allocations (size <= 32 kbytes) ○ Large Allocations 50

Slide 51

Slide 51 text

Go’s Allocator - Large Allocations 51 1 page 2 pages ... > 255 pages Span Span Span Span Span Span mheap Busy Spans Span Span Span Antes de alocar, mheap faz o sweep do mesmo número de paginas

Slide 52

Slide 52 text

Go’s Allocator - Large Allocations 52 1 page 2 pages ... > 255 pages Span Span Span Span Span Span Span Span Span Span Span mheap Free Spans

Slide 53

Slide 53 text

Go’s Allocator - Large Allocations 53 1 page 2 pages ... > 255 pages Span Span Span Span Span Span mheap Free Spans Span Span Span Span Span mtreap ⇒ randomized binary tree

Slide 54

Slide 54 text

Go’s Allocator - Large Allocations 54 Depois de alocar, dependendo da quantidade de memória em uso... ● A goroutine pode ter que trabalhar para o GC ● Stop the World

Slide 55

Slide 55 text

Go’s Allocator - Small Allocations 55 P 1 mcache Cada processador lógico (P) tem um cache local (mcache) P 2 mcache

Slide 56

Slide 56 text

Go’s Allocator - Small Allocations 56 P 1 P 2 mcache mcache Cada mcache mantem um span para cada tamanho (size class) Span Span ... class 1 class 2 Span Span ... class 1 class 2

Slide 57

Slide 57 text

Go’s Allocator - Small Allocations 57 class bytes/obj bytes/span objects 1 8 8192 1024 2 16 8192 512 3 32 8192 256 4 64 8192 170 ... 65 28672 57344 2 66 32768 32768 1

Slide 58

Slide 58 text

Go’s Allocator - Small Allocations 58 P 1 mcache mcache retorna o endereço de um objeto livre no span Span Span ... class 1 class 2 Span

Slide 59

Slide 59 text

Go’s Allocator - Small Allocations 59 P 1 mcache mcache pede um novo span para o mcentral dessa size class Span Span ... class 1 class 2 Span

Slide 60

Slide 60 text

Go’s Allocator - Small Allocations 60 P 1 mcache Cada mcentral tem duas listas, empty e nonempty spans Span Span ... ... class 1 class 2 mcentral mcentral Span Span Span Span

Slide 61

Slide 61 text

Go’s Allocator - Small Allocations 61 P 1 mcache Span com objetos livres vai ser entregue ao mcache Span ... ... class 1 class 2 mcentral mcentral Span Span Span Span

Slide 62

Slide 62 text

Go’s Allocator - Small Allocations 62 P 1 mcache mcentral vai tentar fazer sweep de spans vazios Span Span ... ... class 1 class 2 mcentral mcentral Span Span If there are no nonempty spans….

Slide 63

Slide 63 text

Go’s Allocator - Small Allocations 63 Se nada funciona, mcentral vai pedir um novo span para a mheap class 0 mcentral Span Span mheap

Slide 64

Slide 64 text

Go’s Allocator - Small Allocations 64 mcentral vai dar esse span para a mcache class 0 mcentral Span Span mheap Span

Slide 65

Slide 65 text

Go’s Allocator - Tiny Allocations Alocações para objetos sem pointers menores que < 16 bytes The main targets of tiny allocator are small strings and standalone escaping variables. On a json benchmark the allocator reduces number of allocations by ~12% and reduces heap size by ~20%. 65

Slide 66

Slide 66 text

66 Go’s Allocator - Tiny Allocations 64 bytes Allocated Free Allocated Free ● Cada P mantem um objeto de 64-bytes que foi alocado de um span ● Cada tiny allocation adiciona um subobjeto ao final do objeto ● O GC não sabe sobre esses subobjetos!

Slide 67

Slide 67 text

67 Go’s Allocator - Tiny Allocations Allocated Free mcache P 1 ● Pega um novo bloco do mcache ≃ small allocation ● Eventualmente, o GC vai coletar o bloco antigo Free P 1 mcache

Slide 68

Slide 68 text

Garbage Collector ⇒ Concurrent mark and sweep 68 Go’s Allocator - Sweeping 1. Scan all objects 2. Mark objects that are live 3. Sweep objects that are not live

Slide 69

Slide 69 text

● Runtime periodicamente devolve memória ao OS ● Devolve spans que foram garbage collected a mais de 5 minutos ● No Linux, usa a syscall madvise(2) 69 Go’s Allocator - Devolvendo memória ao OS madvise(addr, size, _MADV_DONTNEED)

Slide 70

Slide 70 text

Analisar alocações ● runtime.ReadMemStats ● pprof ● go tool trace 70

Slide 71

Slide 71 text

71 stats := runtime.MemStats{} runtime.ReadMemStats(&stats) type MemStats struct { ... // Heap memory statistics. HeapAlloc uint64 HeapSys uint64 HeapIdle uint64 HeapInuse uint64 HeapReleased uint64 HeapObjects uint64 ... }

Slide 72

Slide 72 text

Referências 1. http://goog-perftools.sourceforge.net/doc/tcmalloc.html 2. https://www.ardanlabs.com/blog/2017/05/language-mechanics-on-stacks-and-pointers.html 3. https://gabrieletolomei.wordpress.com/miscellanea/operating-systems/in-memory-layout/ 4. Lec 10 | MIT 6.172 Performance Engineering of Software Systems, Fall 2010 5. https://faculty.washington.edu/aragon/pubs/rst89.pdf 6. http://man7.org/linux/man-pages/man2/mmap.2.html 7. http://man7.org/linux/man-pages/man2/madvise.2.html 8. https://github.com/andrestc/linux-prog/blob/master/ch7/malloc.c 72

Slide 73

Slide 73 text

Obrigado! andrestc.com @andresantostc 73