SlideShare a Scribd company logo
1 of 39
shared_ptrとゲームプログラミングでのメモリ管理
@DADA246
自己紹介
• ゲームプログラマやってます
• 家庭用からモバイル、業務用まで幅広く書いてきました
アジェンダ
• はじめに
• メモリリーク
• メモリ断片化
• 処理速度
• まとめ
今回の話の対象
• ハード:OSとゲームが動作するコンピュータ
• ソフト:C++によるネイティブクライアント
• ゲーム:アクションゲームなど、リアルタイム性が問われる
ジャンル
• 開発規模:中規模~大規模
ゲームプログラムの特徴
• フレームレートが安定している(60fps,30fps…)
→スワップアウトが発生しない
→実行時メモリサイズが物理メモリサイズに収まっている
メモリ管理の種類
• メモリ固定管理
→ゲーム起動時に確保されたメモリのみ使用して、ゲーム中は
OSからメモリ確保を行わない方式
• メモリ動的管理
→ゲーム動作中にメモリが必要になった時点でOSからメモリを
確保して、メモリが不必要になったらOSにメモリを返却する方式
→今回の話はコチラ
なぜメモリの動的管理?
• 近年の中規模~大規模ゲーム開発ではレベルデータ、グラ
フィックスリソース、サウンドなど、ゲームが扱うデータが増え
ている
→ゲームをデータドリブンで動作させる必要がある
→メモリを動的管理にすると、メモリによる制限が減るので、
多彩なデータを動作させることができる
試行錯誤
• ゲームが多彩なデータを扱えると、ゲームデザイナやアー
ティストが思いついたアイデアを試行錯誤できる
→メモリの動的管理を行うことで、「一時的にメモリを使用する
が、ゲームが面白くなりそうなデータ」を試すことが出来る
ゲームシーケンス
• メモリの動的管理を行うことで、シーケンスごとにメモリ構成
が大幅に異なるゲームを作ることが出来る
• 例:FPS
レベルプレイでは大量のゲームオブジェクト、AI、ネットワークに
メモリを割り当てるが、カットシーンではそれらの代わりにグラ
フィックスリソースにメモリを割り当てる
メモリ動的管理の問題
• メモリの動的管理にはメリットが多いが、問題点もある
メモリリーク
メモリ断片化
処理速度
→これらの問題点を解決する
メモリリーク
• std::freeやdeleteを書き忘れると発生する
• メモリ解放を他のプログラマに委ねるインターフェースでも
メモリリークは発生しやすい
void Sample()
{
void* pBuffer = std::malloc(1024);
Player* pPlayer = new Player();
}//メモリリーク発生
void Register() { m_pPlayer = new Player(); }
//呼び忘れるとメモリリークする
void UnRegister() { delete m_pPlayer; }
RAII
• Resource Acquisition Is Initialization
• オブジェクトの生存時間とリソースを結びつける
• 基本的にこの設計を守ればメモリリークは起きない
• 実装の一例として、shared_ptrを利用する
shared_ptr
• newとdeleteは使わずにshared_ptrを使う
• 各種モジュールごとにshared_ptrで分離させておくと、生ポイ
ンタを扱わずに済む
class Player
{
private:
std::shared_ptr<Collision> m_collision;
std::shared_ptr<Sound> m_sound;
}
クラスの所有
• クラスを直接所有してInitialize()するのではなく、shared_ptr
にしてコンストラクタで初期化する
→C++の言語設計に従うことで、RAIIを実装しやすくなる
コンストラクタとデストラクタを活用する
Player::Player()
{
m_life.Initialize();
}
Player::Player()
{
m_life = std::make_shared<Life>();
}
メモリリークは発生する?
• バイナリデータ読み込みなど、shared_ptrを使わずに
std::mallocを使う場合もある
→RAIIを守るのが基本だが、std::freeを書き忘れることがある
→メモリリークが発生する
→この場合はメモリリーク検出ツールで対応する
カスタムアロケータ
• あらかじめメモリの確保、開放時にデバッグ情報を保存できる
カスタムアロケータを作り、OSのアロケータを切り替えておく
→デバッグ情報をログ出力することでメモリの状態を把握できる
ゲーム
デバッグ情報の保存
アロケータ
void* _cdecl operator new (size_t size)
{
//カスタムアロケータ呼び出し
}
メモリリーク検出ツール
• ゲームプログラムにおいて、メモリリークが問題になった時のメ
モリ状態を考える
• メモリリークしているアドレスは開放されない
→メモリの生存時間が長いアドレスはメモリリークの可能性が高い
→アドレスに日付をつけるとメモリの生存時間を計算できる
struct Node
{
int64_t address;
int64_t size;
int64_t date;
}
生存時間の長いアドレス
• 常駐データなど、メモリ確保後に解放しないデータもある
• メモリ確保時にコールスタックを保存して、ログ出力に含める
→コールスタックが1回のみ記録されているものは常駐データ
→同一コールスタックが複数回記録されているものはメモリリー
クの可能性が高い
• コールスタックはRtlCaptureStackBackTraceなどで取得できる
メモリリーク検出ツール
• 同一のコールスタックから、生存時間の長いメモリを複数回確保
している箇所はメモリリークしていると判断できる
→エージングなどの自動テストに組み込むことで、メモリリークを自
動的に検出できる
struct Node
{
int64_t address;
int64_t size;
int64_t date;
int64_t backTraceHash;
}
//keyはbackTraceHash
std::map<int64_t,std::vector<Node>> nodes
for(auto it = nodes.cbegin(); it != nodes.cend(); ++it)
{
if( 1 < it->second.size() )
{
auto memoryLeak = it->second;//メモリリーク発見!
}
}
アジェンダ
• はじめに
• メモリリーク
• メモリ断片化
• 処理速度
• まとめ
メモリ断片化
• メモリ断片化とは何か
→メモリの確保と解放を繰り返すことで、連続したメモリが確保
出来なくなる
→メモリの確保に失敗することになる
連続したメモリ領域
• ゲームから見て連続したメモリ領域はMMUの有無で変わる
MMUが有る場合は仮想アドレス空間
MMUが無い場合は物理アドレス空間
• ハードウェア構成によって断片化のしやすさが変わる
→メモリ戦略が変わってくる
MMU非搭載の場合
• 物理アドレス空間の断片化に気をつける必要がある
• 低コストの組み込みマシンの場合が多いので、処理性能を
考えると、メモリ固定管理の方が適している場合もある
例:物理メモリ16MByte程度の
組み込みハードウェアなど Physical memory
MMUが搭載されている場合
• MMUを搭載していて、仮想アドレス空間と物理メモリ量に差が
ある場合
→仮想メモリ空間の大きさに頼る
• フレームレートを維持するというゲームの特性上、ソフトウェア
の規模が物理メモリ量に収まるサイズになることを利用する
Virtual memory Physical memory
断片化対策
• 例:64bit Windows8.1
→プロセスあたりの仮想メモリ空間は128TByte
→ページ単位のブロックアロケータを使い、仮想メモリ断片化は
気にしない
• Windowsのlow fragmentation heapが参考になる
• 断片化よりもアロケータの適切なページ管理が重要
断片化対策
• MMUを搭載していて、仮想アドレス空間と実メモリに差が少
ない場合(32bitコンピュータにGByte単位の実メモリを載せて
いる場合など)
→仮想アドレス空間の断片化に気をつける必要がある
• 例: 32bit Windows XPで、メモリ使用量2GByteのゲーム
Virtual memory Physical memory
断片化対策
• 仮想アドレス空間と実メモリに差が少ないマシンでメモリ断片
化を防ぐには?
→生存時間の長いメモリを減らす
→生存時間の長いメモリと、生存時間の短いメモリのアドレスを
離す
Virtual memory Physical memory
生存時間の長いメモリを減らす
• shared_ptrの相互参照を減らして、一つのshared_ptrを削除
すると、所有しているshared_ptrが削除されるようにしておく
→シンプルに大量のモジュールを作り直すことが出来る
メモリの生存時間が短くなるので、ゲームが長時間駆動に耐え
やすくなる
• デバッグ機能など依存関係が
増えやすいものはweak_ptrにする
shared_ptr
shared_ptr shared_ptr
生存時間の長いメモリを減らす
• ゲームシーケンスの切り替え時にモジュールを作りなおすよ
うにする
• シーケンス間のデータ移行のためのモジュールを作ることも
ある
void LevelClear()
{
std::shared_ptr<Status> status = m_level->GetStatus();
m_level = std::make_shared<Level>(status);
}
生存時間の長いメモリを減らす
• シングルトンなど、グローバルインスタンスは極力使わない
→デバッグモジュールなど、グローバルインスタンスになりやす
いものもある
• グローバルインスタンスはゲーム開始直後など、他のメモリ
アロケーションが走る前にメモリを確保して、断片化された領
域を作らないようにする
グローバルインスタンス→
Virtual Memory
空き領域→
断片化対策
• 生存時間の長いメモリと、生存時間の短いメモリのアドレスを
離す
→アロケータを複数用意する
Double Ended Stack allocatorを使うこともある
Virtual Memory
VRAM
• 物理アドレス空間の断片化に気をつける必要がある
(GPUによっては仮想アドレスに対応している場合もある)
• 断片化しやすいが、いざとなったらメモリコンパクションを実
装することもできる
→リソースをハンドルで管理していることが多いため
VRAM
アジェンダ
• はじめに
• メモリリーク
• メモリ断片化
• 処理速度
• まとめ
処理速度
• ある程度メモリ確保を高速化した上で、その処理速度に見
合ったゲームにする
→Win32のHeapAllocなど、Kernel-landで実行されるアロケータ
ではなく、User-landで実行される独自のカスタムアロケータを用
意する
• メモリ動的管理ではメモリ確保が頻繁に実行されるので、メ
モリ固定管理よりも処理が重いと言われることはあるが、こ
れは開発環境の良さとのバランスの問題
メモリ動的管理の問題点と解決方法
• メモリリーク → RAII(shared_ptr)とメモリリーク検出ツールで解決
• メモリ断片化 → 仮想アドレス空間の広さを活用して解決
• 処理速度 → アロケータを高速化しつつ、処理速度に見合った
ゲームにすることで解決
メモリが不足したら?
• メモリが不足しないようにゲームを作るのが基本
→自動テストやエージングを繰り返して、メモリ使用量を把握する
• メモリリークとメモリ断片化を解決してもメモリが不足する場合は、
ゲームに対してデータが大きすぎるので、データを修正する
auto player = std::make_shared<Player>();
player->Update(); //playerは必ず存在する
まとめ
• メモリの動的管理が可能になったことで、ゲーム上で多彩な
データを動作させることが可能になった
→ゲームデザイナやアーティストのクリエイティビティを引き出し
て、もっとゲームを面白くしよう!
Questions?
ご静聴ありがとうございました

More Related Content

What's hot

オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
Moriharu Ohzu
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
MITSUNARI Shigeo
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
Norishige Fukushima
 

What's hot (20)

SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介SSE4.2の文字列処理命令の紹介
SSE4.2の文字列処理命令の紹介
 
オンラインゲームの仕組みと工夫
オンラインゲームの仕組みと工夫オンラインゲームの仕組みと工夫
オンラインゲームの仕組みと工夫
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 
C++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングC++ マルチスレッドプログラミング
C++ マルチスレッドプログラミング
 
プログラムを高速化する話
プログラムを高速化する話プログラムを高速化する話
プログラムを高速化する話
 
MagicOnion入門
MagicOnion入門MagicOnion入門
MagicOnion入門
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
RPGにおけるイベント駆動型の設計と実装
RPGにおけるイベント駆動型の設計と実装RPGにおけるイベント駆動型の設計と実装
RPGにおけるイベント駆動型の設計と実装
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
 
Riderはいいぞ!
Riderはいいぞ!Riderはいいぞ!
Riderはいいぞ!
 
いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
目grep入門 +解説
目grep入門 +解説目grep入門 +解説
目grep入門 +解説
 
DSIRNLP #3 LZ4 の速さの秘密に迫ってみる
DSIRNLP #3 LZ4 の速さの秘密に迫ってみるDSIRNLP #3 LZ4 の速さの秘密に迫ってみる
DSIRNLP #3 LZ4 の速さの秘密に迫ってみる
 
なぜなにリアルタイムレンダリング
なぜなにリアルタイムレンダリングなぜなにリアルタイムレンダリング
なぜなにリアルタイムレンダリング
 
明日使えないすごいビット演算
明日使えないすごいビット演算明日使えないすごいビット演算
明日使えないすごいビット演算
 
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭するCEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する
 
ゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめ
 
不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray不遇の標準ライブラリ - valarray
不遇の標準ライブラリ - valarray
 

Similar to shared_ptrとゲームプログラミングでのメモリ管理

実体験に基づく、少人数制作によるシューティングゲームの提案
実体験に基づく、少人数制作によるシューティングゲームの提案実体験に基づく、少人数制作によるシューティングゲームの提案
実体験に基づく、少人数制作によるシューティングゲームの提案
IGDA Japan
 

Similar to shared_ptrとゲームプログラミングでのメモリ管理 (7)

パソコン選び(抜粋)
パソコン選び(抜粋)パソコン選び(抜粋)
パソコン選び(抜粋)
 
Reinvent2017 recap-gaming-session-2
Reinvent2017 recap-gaming-session-2Reinvent2017 recap-gaming-session-2
Reinvent2017 recap-gaming-session-2
 
第8回テックヒルズIBM資料
第8回テックヒルズIBM資料第8回テックヒルズIBM資料
第8回テックヒルズIBM資料
 
ゲームの仕様書を書こう2 仕様書に記載する機能内容
ゲームの仕様書を書こう2 仕様書に記載する機能内容ゲームの仕様書を書こう2 仕様書に記載する機能内容
ゲームの仕様書を書こう2 仕様書に記載する機能内容
 
ゲームインフラコンテナ実践導入
ゲームインフラコンテナ実践導入ゲームインフラコンテナ実践導入
ゲームインフラコンテナ実践導入
 
実体験に基づく、少人数制作によるシューティングゲームの提案
実体験に基づく、少人数制作によるシューティングゲームの提案実体験に基づく、少人数制作によるシューティングゲームの提案
実体験に基づく、少人数制作によるシューティングゲームの提案
 
Amazon Game Tech アマゾンゲームテクノロジー - Amazon Game Tech - GTMF 2018 OSAKA
Amazon Game Tech アマゾンゲームテクノロジー - Amazon Game Tech - GTMF 2018 OSAKAAmazon Game Tech アマゾンゲームテクノロジー - Amazon Game Tech - GTMF 2018 OSAKA
Amazon Game Tech アマゾンゲームテクノロジー - Amazon Game Tech - GTMF 2018 OSAKA
 

shared_ptrとゲームプログラミングでのメモリ管理