Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Goならわかる Linuxのメモリ管理

Goならわかる Linuxのメモリ管理

Jumpei Takiyasu

August 22, 2018
Tweet

More Decks by Jumpei Takiyasu

Other Decks in Technology

Transcript

  1. x86_64のLinuxで実行すると、何が表示される? 実行環境: go 1.10 / Linux version 4.18.0-rc8 / Intel(R)

    Core(TM) i7-8650U、デバッガはmain.mainでbreak 1. hoge 2. 0x0 - 0x528000 のどこか 3. 0x528000 - 0x547000 [heap] のどこか 4. 0x7ffffffde000 - 0x7ffffffff000 [stack] のどこか 5. 2,3,4以外の領域のどこか 6. それ以外 func main() { a := "hoge" fmt.Println(&a) } (gdb) i proc mappings process 26627 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x400000 0x483000 0x83000 0x0 /home/juntaki/memory/quiz/main 0x483000 0x514000 0x91000 0x83000 /home/juntaki/memory/quiz/main 0x514000 0x528000 0x14000 0x114000 /home/juntaki/memory/quiz/main 0x528000 0x547000 0x1f000 0x0 [heap] 0xc000000000 0xc000001000 0x1000 0x0 0xc41fff8000 0xc420100000 0x108000 0x0 0x7ffff7f5a000 0x7ffff7ffa000 0xa0000 0x0 0x7ffff7ffa000 0x7ffff7ffd000 0x3000 0x0 [vvar] 0x7ffff7ffd000 0x7ffff7fff000 0x2000 0x0 [vdso] 0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack] 0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
  2. エスケープ解析でヒープorスタックが決まる ヒープになっちゃうのはfmt.Println()にポインタを渡してるためです $ go build -gcflags '-m -N -l' alloc.go

    # command-line-arguments ./alloc.go:9:13: a escapes to heap ./alloc.go:8:10: new(int) escapes to heap ./alloc.go:9:13: main ... argument does not escape ./alloc.go:11:10: main new(int) does not escape func main() { a := new(int) // ヒープに取れる fmt.Println(a) b := new(int) // スタックに取れる *b = 0xdeadbeef }
  3. 呼び出し規約とスタックの仕組み やきにく たべたい package main func main() { yakiniku() }

    //go:noinline func yakiniku() { tabetai(0xdeadbeef) } //go:noinline func tabetai(a int) { a++ }
  4. 関数を呼び出すだけの関数をみる 要するに$spが指していて書き込み可能なら別に決まった場所じゃなくてもよい mov %fs:0xfffffffffffffff8,%rcx cmp 0x10(%rcx),%rsp jbe 44c1b5 <main.yakiniku+0x35> sub

    $0x10,%rsp mov %rbp,0x8(%rsp) lea 0x8(%rsp),%rbp mov $0xdeadbeef,%eax mov %rax,(%rsp) callq 44c1c0 <main.tabetai> mov 0x8(%rsp),%rbp add $0x10,%rsp retq callq 444570 <runtime.morestack_noctxt> jmp 44c180 <main.yakiniku> スタックが足りなくなる場合は runtime.morestackで拡張 スタックに%rbpと、引数を積む callで、戻り番地が積まれる スタックを元に戻す caller’s rbp 引数 rbp 戻り番地 rsp
  5. 参考資料 malloc動画はオススメ malloc動画 [The 67th Yokohama kernel reading party -

    YouTube] (https://www.youtube.com/watch?v=0-vWT-t0UHg) Goのメモリ管理(特にスタックのはなし) [Five things that make Go fast | Dave Cheney] (https://dave.cheney.net/2014/06/07/five-things-that-make-go-fast) [Why is a Goroutine’s stack infinite ? | Dave Cheney] (https://dave.cheney.net/2013/06/02/why-is-a-goroutines-stack-infinite) [Contiguous stacks] (https://docs.google.com/document/d/1wAaf1rYoM4S4gtnPh0zOlGzWtrZFQ5suE8qr2sD8uWQ/pub) main.mainより前には何が起きるか [Golang Internals, Part 6: Bootstrapping and Memory Allocator Initialization | Altoros] (https://blog.altoros.com/golang-internals-part-6-bootstrapping-and-memory-allocator-initialization.html)