Más contenido relacionado
La actualidad más candente (7)
Similar a GCをみればRTSが見えてくる、かも。。。 (20)
GCをみればRTSが見えてくる、かも。。。
- 2. 自己紹介
● ID: dec9ue
● 属性:組み込みエンジニア
●
言語遍歴
● N88-BASIC ← 高校生: PC持ってなかった
● SML/OCaml ← 学生時代:大堀/雅利賀先生
● C++ ← 社会人
● Java ← プロジェクト変わった
● C ← 更にプロジェクト変更: お金を稼ぐ気になった
● Verilog? ← HW開発部署になった、いまここ
● 正直、sortのアルゴリズムはかわいいと思う。
- 6. GC ってなんだっけ
● いちおー確認しておきます。
● Garbage Collection (or Collector)
●
ヒープメモリの開放を自動化する仕組みの総称
- 7. GC の流派
● おおよそ、4流派に分かれる
● 「ガベージコレクションのアルゴリズムと実装」から記憶
に基づいて念写
明示的開放 オブジェクト 主な処理系
の移動
マークスイープGC あり なし Java(コピーも併用)
Dalvik
Cruby
OCaml
参照カウント法 あり なし Cpython(MSも併用)
コピーGC なし あり GHC RTS
Java(MSも併用)
マークコンパクトGC 実施可能 あり Lisp2
- 8. コピーGC
● 方法
●
「生きているオブジェクト」を別領域にコピーすることで必
要なものだけを残す。
●
コピっただけではリンク先がずれちゃうので、ポインタを
書き換えて移動後のオブジェクトをさすようにする
From space gbg gbg
To space
- 9. コピーGC
● 方法
●
「生きているオブジェクト」を別領域にコピーすることで必
要なものだけを残す。
●
コピっただけではリンク先がずれちゃうので、ポインタを
書き換えて移動後のオブジェクトをさすようにする
From space gbg gbg
To space
- 10. コピーGCの特徴
● メリット
● フラグメントを小さくできる
– コピーした際にオブジェクトの隙間を詰められる
● (やり方によっては)関連の強いオブジェクトを近くに配置できる
● アロケーションの単価が安い
– free領域ポインタをずらすだけとかで実現
● 実はデアロケーションの単価も安い
– コピー元においてきて見捨てるだけ
– → 実は生存オブジェクトにコストがかかる
● つまり生存オブジェクトの比率が低いほどGC効率が向上
– THUNK評価するだけでゴミを生じるHaskellにピッタリ!
- 11. コピーGCの特徴
● デメリット
● GC処理自体が重い。
– トラバースするだけでなく、生存オブジェクトは丸コピー
● World Stopping
– 基本的にGC中は実行系(mutator)は全停止
– インクリメンタルな処理は苦手
– 保守的GCも苦手
– ↑ポインタの移動処理に起因する
● Finalizer的処理はできない
– 何を棄てたのか判別できないため。。。
- 12. Cheneyのアルゴリズム
● オブジェクトを幅優先でコピー
● To-spaceをキューとして利用
●
管理データが小さい
● ポインタ/非ポインタの区別 と オブジェクトサイズの
管理は必須
From space
To space
処理完了 処理待ち
limit free
- 14. GHCのGC
● Cheneyのアルゴリズムをベースに下記を加えた。
● Large Object
● 世代別GC
● Eager Promotion
● Parallel GC
● 一応、MarkSweepのオプションも残している
● 特徴
● World Stopping
– ConcurrentとかIncrementalでない
– すべてのMutator(Capabilityというべきか)をGC時に停止
- 15. GHCのGCの基本動作
● Evacuate & Scavenge
● While/Field[1996]によると
– Evacuate ← From Spaceのオブジェクトに対する処理
● オブジェクトをFrom→Toにコピーする処理。
● Forwarding Addressをコピー元に残す。
● Toにコピーされた新オブジェクトはScavenge Queueに入る。
– Scavenge ← To Spaceのオブジェクトに対する処理
●
対象のオブジェクトが指しているオブジェクトが初めて出会うオブジェ
クトであればEvacuateする。
● 対象オブジェクト内のポインタはToに移動後のポインタに書き換え
る。
- 16. GHCのGCの実動作
● Evacuation(Fromでの動作)
● From->Toへコピー
● オブジェクトの中にForwarding Pointerを書き込む
● Toのfreeポインタを動かす
● ※↓1が参照先の2と5をEvacしているの図
From space 1 2 3 4 5 6
To space 1 2 5
- 17. GHCのGCの実動作
● Scavenge(Toでの動作)
● 参照先にForwarding Pointerがない時(未Evacの時)Evacuateする
● 参照先へのポインタをForward先に書き換える
● Scav中にlimitとfreeがピッタンコしたら終了
● ※↓5がScavされてますの図
From space 1 2 3 4 5 6
To space 1 2 5 3
free
- 18. GHCのGCの実動作
● Forwarding Pointerって何さ、どこさ?
● みんな大好き Info Table
– http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts
/Storage/HeapObjects
● FromオブジェクトのInfo Tableポインタを書きつぶす
– ヘッダ内のInfo Table用ポインタの下1ビットが立っていると
Forwarding Pointer
Forward先へ!
- 19. GHCのGCの実動作
● rts/sm/GC.c の GarbageCollect関数
– https://github.com/ghc/ghc/blob/master/rts/sm/GC.c
● Evacuate フェーズ
– ルートと思しき物体たちからの参照をEvacuateしていく
● scavenge_capability_mut_lists
● markCapabilitiy
● markCAFs
● markSignalHandlers
● markWeakPtrList
● markStablePtrTable
● Scavenge フェーズ
– To spaceのキューを走査してScavengeをすすめる。
- 20. Large Object
● と、ここまで説明してきたのは実はページ未満の小
さなオブジェクトについての話、、、、
● Large Objectとは
● ページを超えるような大きなオブジェクト
● Large Objectは
● コピーのコストが大きい
●
小さいオブジェクトに混在してアラインメントの影響を受
けるともったいない
- 21. Large Object
● Large Objectは独立管理!
● これはevacuate時にコピーではなく、リストのつなぎ換
えをしている
● 実質的にはMark & Sweepになっている
●
明示的なブロック解放処理が行われる
- 22. 世代別GC
● GCの範囲を狭くする工夫
● 大半のオブジェクトは生まれた次のGCで死亡
● 範囲を絞ってGCしたらいいやん!
Gen 2 Gen 1 Gen 0
gbg gbg
- 23. 世代別GC
● 逆リンクによる世代の破壊
● ThunkやmutableオブジェクトがElder Genに存在する
と、Youger Genを走査するだけではすまなくなる。
Gen 1 Gen 0
gbg gbg
- 24. 世代別GC
● 逆リンクによる世代の破壊
● ThunkやmutableオブジェクトがElder Genに存在する
と、Youger Genを走査するだけではすまなくなる。
● → Remembered Set!
● Commentaryのページ貼る
● 実際にはCapabilityごとのmut_listで管理される
Gen 1 Gen 0
gbg gbg
- 25. 世代別GC
● Remembered Setを作るのはMutator側の仕事
● 排他を避けるためCapabilityごとにリストがある
● Remembered Setを残すためのコード
● rts/Capability.hの
– recordClosureMutated / recordMutableCap
– Capabilityのmut_listへ書き込む処理
● Mutatorからの呼び出し例
● rts/Update.hの
– updateWithIndirect
– 上書き対象オブジェクトがgen 0以外ならmut_listへ書き込む
- 26. AgingとPromotion
● Promotion : 親世代に移動
● Aging : 親世代に移動する基準
● 一般的なAgingの仕組み
● 「年齢」を表すカウンタを利用する
● GHCは。
● 明示的なAgingをやめてしまった。。。
● Aging 即 Promotion
●
- 27. Eager Promotion
● リンク元のオブジェクトがelder generationにいる
場合、リンク先もelder generationにいてほしい
● 典型的な例:リストの未評価THUNKを潰したら新しい
Listノードができた
● Eager Promotionによりevacuation時にElder Genへ
移動
● 実装: Evac.cのalloc_for_copy関数
Eager Promotion
gbg gbg
- 28. Parallel GC
● Scavenge処理を複数コアで処理して高速化する
仕組み
● SMPシステムでのスループット向上のために入れられ
たクソ設計(と敢えて言わせていただこう)
● いうなれば、業務停止で総出でクリーンアップ大作戦
- 30. Local GC
● SMPなシステムを考えるとWorld Stopping GCは
応答性の観点でクソ
● どれかスレッド応答しろよ
● 昔のSMPかよ
● まぁ、スレッドが応答すりゃいいってもんでもないが
● ていうか、スレッド単位でできることいっぱいあるで
しょ。なんで頑張らないの?
● あきらめたらそこで試合終了ですよ
- 31. Local GC
● アロケーション管理をスレッドごとに実施
●
マイナー領域はスレッド単位
● スレッド間共有されるオブジェクトはPromoteされる
● メジャーGCはグローバルなのでWorld Stopping
● コピーGCの宿命
- 32. Local GC
● 試行結果(8コア並行実行)
● スループット10% UP (おおっ!)
● メジャーGCによる停止時間は3m->6ms (あれ?)
● hackage.haskell.org/trac/ghc/blog/new-gc-preview
● Local GC関連は結構想像で嘘書いてるかも。。。
● (すいません。。。)
- 33. GHCコードを読んでみた感想
● STGのシンプルさに対してRTSは魔窟
● Taggingはある程度は仕方ない
●
型キャスト前提の設計とか当たり前
– Infotable 構造ェ。。
● 古い設計を残しながらの改修
●
コード生成系との見えない規約
– これも多少は仕方ないかもだが、、、
● もっとシンプルな設計が望まれることダヨ!
●
改造に対する障壁になってるので実行系の世代交代が
必要なのでは。。。