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

Gotanda.unity #10 メモリと闘う者達 〜GC編〜

Nozomi Tanaka
January 23, 2019
2.9k

Gotanda.unity #10 メモリと闘う者達 〜GC編〜

21Pに誤記
誤:クラス型にする? それとも参照型?
正:クラス型にする? それとも値型?

誤記、どっちも同じ・・・

Nozomi Tanaka

January 23, 2019
Tweet

Transcript

  1. メモリと闘う者達
    〜GC編〜
    Nozomi Tanaka / @nozomin770
    Gotanda.unity #10 2019/1/23

    View full-size slide

  2. Tanaka Nozomi(タナカ ノゾミ)
    ・ワンダープラネット株式会社 - グローバルスタジオ所属
    ・Unity使い4年半、Cocos2d-xもはじめました
    ・Ruby、PHPなどを使ったサーバーエンジニアでもあります
    ・プロジェクトマネジメントとインフラの修行もはじめました
    ・Twitter:@nozomin770

    View full-size slide

  3. アジェンダ
    ・1分でわかるメモリの仕組み
    ・C#とGC
    ・GCで死ぬ(フリーズする)ゲームを救えないのか
    ・ボックス化、ラムダ式、クラス型と構造体、愉快な仲間たち
    ・まとめ

    View full-size slide

  4. これは、GCと戦う
    熱き勇者達の物語である

    View full-size slide

  5. 1分で分かるメモリ管理
    メモリには2種類の保存場所があります
    「スタック」という場所と
    「ヒープ」という場所の2つです

    View full-size slide

  6. スタックのルール
    先入れ、先出し、隙間なし
    隙間なく積み上げるため効率がいい

    View full-size slide

  7. ヒープのルール
    空いているところにうまいこと入れる
    隙間あり、効率はよくない

    View full-size slide

  8. 全部スタックだと効率がよいのでは?
    ・スタックが使えるときは限られている
    ・プリミティブ型はスタックを使えると思えばOK
    (object、stringは除く)
    ・その他のほとんどの場合はヒープのメモリを使うことになる

    View full-size slide

  9. ヒープが悪い?
    そういうわけじゃない

    View full-size slide

  10. C#のメモリとの付き合い方
    ・C#はガベージコレクション(以下GC)という仕組みで
    メモリの片付けを自動管理してくれている
    ・GCが走るとき、UnityではGC終了まで処理が停止してしまう
    (俗に言う処理落ち)

    View full-size slide

  11. GCの発生条件をつかもう
    ・OSの物理メモリが足りない場合
    ・利用可能なヒープメモリの使用量が一定のしきい値を超えた場合
     なおしきい値は常に変動する(!?)
    ・GC.Collectメソッドが呼び出された場合

    View full-size slide

  12. GCが走る世界線を
    回避できないのか・・・?

    View full-size slide

  13. GCの動作原理を支配する
    ・C#のGCは「到達可能性」を見て回収可能な変数を見ます
    ・「到達可能性」の変動条件
    →ヒープ領域へのメモリ確保(アロケート)が原因
    →これは変数宣言時に行われる

    View full-size slide

  14. 到達可能性の変動を抑える
    ・ヒープ領域への確保が行われる条件
    - ボックス化(ボクシング)
    - クラス型のオブジェクト生成
    ・上記を回避するようにコードを書くことでGCが走らない世界線にたどり
    着けるはずだ・・・

    View full-size slide

  15. どうやって・・・

    View full-size slide

  16. ボックス化とは
    ・値型をobject型(参照型)として扱うとき、スタック上からヒープ上に値を
    コピーする処理を「ボックス化」(boxing)と呼びます
    ・値型を使いながらもヒープ領域を使ってしまうため、(個々は僅かだが)
    無駄に重くなる
    ・ヒープ領域へのアロケートが行われてしまう(GCを誘発する可能性が
    生まれる)

    View full-size slide

  17. ボックス化を(適度に)避けたい
    - メソッド引数がobject型になってないか気をつける
    - Equalsは生で使うとobject引数が多い…
    - 比較対象クラスへのIEquatableインターフェース実装がお
    すすめ
    - 一部のUnityのクラスはDictionaryでボックス化が起きる
    - structでないクラス
    - またはIEquatableを実装していないクラス
    - UnityEngine.Objectを継承してるクラスに多い

    View full-size slide

  18. とはいってもやりすぎは辛い
    ・ボックス化が起きる条件は値型の取り扱いのミスに多い
    ・int型をobject型に変換
    ・ジェネリックは使ってOK
    ・(Listにintを入れてもboxingされない)
    ・GCが起きていい時はボックス化に気にする必要はない
    (と思ってます・・・)

    View full-size slide

  19. クラス型オブジェクトの生成を回避
    ・ラムダ式の展開式に気をつける
    ・メソッドをラムダ式に入れると展開時にデリゲートをnewする
    ・ラムダ式にメソッドを食わせる場合は大体ゴミが出る
    ・値型以外を使っても勿論ゴミは出る
    ・コアロジックなどループする箇所では注意
    ・ラムダ式にメソッドを入れないのは現実的ではない

    View full-size slide

  20. その他の回避策
    ・事前確保によりゲーム中のアロケートを避ける
    - 確保時に足りないから到達可能性を見る
    - 確保するから到達可能性が変わってしまう
    - GC発生してほしくない時は確保しなきゃいいじゃん理論
    - あんまり現実的ではないかも。インゲーム全体を管理可能な
    規模ならアリ
    ・データクラスはクラスでなく構造体で作る、とか。

    View full-size slide

  21. クラス型にする? それとも参照型?
    ・複製を行わないデータは構造体で作ると良い
    - 値型は代入時に複製が必要で、重くなり得る
    ・「クラスの継承」や「仮想メソッド」など多態性を使いたい場合はクラスで
    作ると良い
    - というかクラスでしかできない

    View full-size slide

  22. その他、これはどうなの編
    - foreachはだめ?
    - IL2CPPがfor文に展開してくれる
    - for文でボックス化が発生しないコードならOK
    - UniRxはだめ?
    - ふつーに使う分には問題ないと思います(内部コードは対策済
    み)
    - オペレータの引数に入れるラムダ式がボックス化を誘発する
    コードの場合、展開時にボックス化すると思います

    View full-size slide

  23. その他、これはどうなの編
    - LINQはだめ?
    - 完全にものによる・・・
    - ラムダ式がある場合はラムダ式の展開式に注意
    - 引数がある場合、値型で送るかジェネリック型で送れるなら
    ボックス化はしないはず
    - LINQの内部実装でボックス化してたら重いLINQメソッドなの
    で諦める

    View full-size slide

  24. まとめ
    - メモリの管理場所「スタック」と「ヒープ」を意識する
    - GCの発生条件を意識する
    - 「到達可能性」を変化させないことで間接的にGC発生率を減ら
    せる
    - 「new」「ボックス化」を抑える
    - ラムダ式は展開時にGCを誘発するケースに注意

    View full-size slide

  25. 参考にさせていただいたHP
    - https://www.slideshare.net/KMC_JP/c-91154309
    - http://neue.cc/2016/01/06_525.html
    - https://www.scriptlife.jp/contents/programming/2017
    /05/14/unite2017-performance/

    View full-size slide

  26. ご清聴
    ありがとうございました

    View full-size slide