Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Go の GC の不得意な部分を克服したい
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
鹿
December 15, 2024
Programming
1.6k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Go の GC の不得意な 部分を克服したい
Kyoto.go #56 オフライン忘年LT会の発表資料です。
https://kyotogo.connpass.com/event/335437/
鹿
December 15, 2024
More Decks by 鹿
See All by 鹿
なぜselectはselectではないのか
taiyow
1
450
Golang と Erlang
taiyow
8
2.2k
Other Decks in Programming
See All in Programming
才能?センス?知らん、 続けたもん勝ちだ。-- 結婚・出産・癌を越えてなお、私がプロダクトを創り続ける理由
16bitidol
2
790
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
技術記事、 専門家としてのプログラマ、 言語化
mizchi
14
7.3k
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
200
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.7k
ランチタイムLT会3周年!ランチタイムLT会を3年間続けられたお話
y0hgi
1
130
継続モナドとリアクティブプログラミング
yukikurage
3
400
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
570
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
160
どこまでゆるくて許されるのか
tk3fftk
0
420
Go1.27で導入されるジェネリクスメソッドでできること
mackee
0
250
Even G2とAWSで推しのエージェントを召喚しよう!
har1101
1
140
Featured
See All Featured
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
750
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Marketing to machines
jonoalderson
1
5.6k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Speed Design
sergeychernyshev
33
1.9k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.4k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
300
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
380
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
180
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
340
Transcript
Go の GC の不得意な 部分を克服したい 鹿 @mizushika1
GC とは • Garbage Collection • 作成したヒープを自動で回収してくれる仕組み • ヒープ →
プログラムが動的に確保するメモリのうち、スタックじゃない方 • 関数をまたいだスコープを持つとか、 スタックに乗せられない大きいサイズを確保するときに使う • Runtime 上で動く言語には大抵ある • 無いのは、C/C++, Rust, Zig, Ada など • イメージで言うと、 • 自分が散らかしている部屋をときどき片付けて ゴミを捨ててくれるお手伝いさん
Go の GC • Full mark and sweep • mark:
ヒープ領域全体を検査して、 使われているものから辿れないものを見つける • 検査漏れしないように mark 中はすべての goroutine を停止する → STW (Stop-the-world) • sweep: 使われていないものを解放する • こちらは並行処理可能、プロセスのCPU能力の25%まで使う • 『効率的なGo』 5.5.3 ガベージコレクションが詳しい • イメージで言うと、 • 毎日の掃除で引き出しやタンスの中のものを全部チェックしているサイコパス
世代別 GC というものも有る • GC をする対象を young と old に分けて
GC の頻度を分ける • 普段は young の方だけ GC を実施 • old はときどき or メモリが不足したときだけ実行 • 大抵のオブジェクトは、短命と長命に分かれる傾向がある • すぐ死ぬやつはすぐ死ぬが、死なないやつはずっと生き残る • old は毎回 GC してもほぼ空振りするので頻度を分ける • Go 以外の大抵の GCed 言語が採用 • イメージで言うと、 • 世代別GCは引き出しやタンスの中は大掃除のときだけチェックして、 普段は机や床を片付けるという普通の掃除
Go の GC の得意/不得意 • 得意: • 確保したヒープが早期に解放されるケース • REST
API のようなアクセスがすぐ終了するようなサービス • 一回実行するだけの CLI ツール • 不得意: • gRPC や WebSocket などを使って常時接続するサービス • 1時間以上などの長寿命のコネクション用のヒープが GCで毎回チェックされる • ※Go の GC がリリースごとに改善されているのは知っているが、 それでも常時接続サービスには厳しい面がある • ヒープオブジェクトが1億個あると STW が 1ms 近くになる • どうにか改善(GC負荷を軽減)したい
強い味方1: arena • GC 対象外の特別なヒープ領域を作れる • Go 1.20 に EXPERIMENTAL
で導入された • proposal: arena: new package providing memory arenas #51317 https://github.com/golang/go/issues/51317 • メリット • 長寿命オブジェクトを作っても GC の負荷が増えない • 自力でメモリ確保 (malloc) して割り当てるのに比べてアロケーションが楽 • デメリット • Arena 単位の管理になる • サイズは最低 8MB • Arena 全体の一括解放しかできない • 「長寿命のコネクション単位で arena を作ろう」と思っても、使用サイズが 8MB 未満だと、 メモリ効率が犠牲になる
強い味方1: arena % GOEXPERIMENT=arenas go build … var ar =
arena.NewArena() func allocate(size int) (string, []int) { str := arena.New[string](ar) is := arena.MakeSlice[int](ar, 0, size) return str, is ) // myArena.Free()
強い味方2: sync.Pool • メモリプールを作る標準パッケージ • プールから確保 (Get) して、使い終わったらプールに戻す (Put) •
毎回オブジェクトを生成して GC で回収されるのではなく、同じオブジェクトを使 いまして生成と回収の回数を減らす仕組み • ただし、毎回 GC 対象になるのは • これを、Pool の確保関数内で arena から取得してあとは Pool 側で管理することで、 解放が不要になり arena の「GC の負荷を増やさない」恩恵だけを受けられる • ただし Put を忘れると真の意味でのメモリリークになるので注意
強い味方2: sync.Pool const bufSize = 1024 var ( ar =
arena.NewArena() mu = sync.Mutex{} bufPool = sync.Pool{ New: func() any { mu.Lock() defer mu.Unlock() return arena.MakeSlice[byte](are, 0, bufSize) }, } } func foo() { buf := bufPool.Get().([]byte) defer bufPool.Put(buf) …
まとめ • Go の GC は様々なバランスを考慮した上で世代別 GC を採用していない • それだと長寿命のヒープオブジェクトが多いケースが不得意(GC
負荷が高い) • 回避策として、 arena でヒープを切り出して、sync.Pool でメモリプールを作ると 良さそう • とはいえ arena がまだ EXPERIMENTAL なので使い勝手は未知
おわり
補足:なぜ Go は世代別 GC を採用しないのか • “Getting to Go: The
Journey of Go's Garbage Collector” が参考になる https://go.dev/blog/ismmkeynote • 2018 年の ISMM (メモリ管理関連の学会?) のキーノート • 発表者の Rick Hudson 氏は Google の Go チームで GC とruntime の研究開発者 • 理由: Write Barrier が十分には早くないため • young と old の間の参照を追跡するために write barrier が必要になる • write barrier の遅延は常に(GC期間外にも)かかるので、ヒープが大きくなるほど(GC回数が 減るほど)相対的にコストが大きくなる、が現状では write barrier は速度面で不利 • つまり:世代別 GC の効果は Go では薄い • 世代別 GC を導入すると GC 中の STW を短縮できるが、Go ではこれは現状は大きな問題に なっていない • 世代別 GC を導入しても GC のスループットは向上しない
補足:arena はいつ標準になるの? • Go 1.20 のリリースは 2023/02 … 2年前? まだ
EXPERIMENTAL なの? • 答え:“Likely never” (ほぼ確実にならない) • https://github.com/golang/go/issues/51317#issuecomment-1676334535 • use-after-free 問題のせい • 通常のポインタから arena 内部のデータを指してから arena を解放すると…?
ほんとうにおわり