2015年3月6日金曜日

cocos2d-xのメモリ対策について

どうも、俺@仕事中です。

昨年、cocos2d-x CCSprite(テクスチャ)の軽量化という記事を書きましたが、
今回も同じようにメモリ対策についてメモ。

■環境
・cocos2d-x 2.2.6
・Xcode 6.1.1

先に結論から言いますと、
CCSpriteFrameCacheやCCTextureCacheの使いすぎに注意、
または、メモリ不足に陥る前に正しくキャッシュデータを解放しましょう。
ということです。

CCSpriteFrameCacheCCTextureCacheは、
スプライトシートなどの画像データをメモリ上にキャッシュしてくれるため、
CCSpriteオブジェクトの生成時に高速&低負荷であることがメリットな反面、
メモリを消費します。(※1)

特にCCSpriteFrameCacheは大きなサイズは画像ファイル(スプライトシート)を
キャッシュすることがあるのでそのメモリ消費には要注意です。


例えば、
タイトル画面(TitleScene) → 遷移 → ゲーム画面(GameScene)
のような場合。

タイトル画面で表示するためのスプライトシートを読み込み、
またゲーム画面でもゲーム画面用のスプライトシートを読み込み、
といった処理を行うと、
両方の画面で読み込まれたスプライトシートはキャッシュされたままになります。




メモリが不足してくると、iOSでは
    AppController#applicationDidReceiveMemoryWarning:(UIApplication *)application; 
がコールされ、
cocos2d-xのバージョンによっては、
    CCDirector#purgeCachedData(void)
が呼ばれて、開発者が意図せず勝手にキャッシュデータが消去されます。

この状態だと、次にCCSpritFrameCacheからキャッシュデータを読み込もうとすると
エラーとなりアプリがクラッシュしてしまいます。


対応として、
1)CCDirector#purgeCachedData(void)を呼ばない。
2)不要になったタイミングでCCSpriteFrameCacheのキャッシュデータをクリアする。
が考えられます。

1)の方法は簡単&すぐに対応できますが、メモリ逼迫の原因は解消されません。
2)は、画面遷移の前などで
    CCSpriteFrameCache::sharedSpriteFrameCache()->removeSpriteFramesFromFile(const char *plist);
を呼べばOKです。

画面遷移の前というのは、
CCDirector#replaceScene(CCScene *pScene)
を呼ぶより前のタイミングです。
その該当するSceneのonExit()やデストラクタ内で、
    CCSpriteFrameCache::sharedSpriteFrameCache()->removeSpriteFramesFromFile(const char *plist);
を呼ぶと、
すでに遷移先のSceneオブジェクトが生成されてしまっているので、
タイミングとしてはちょっと遅いです。

※1) CCSpriteクラスのcreate(const char *fileName)メソッドや
initWithFile(const char *fileName)メソッドは、
内部でCCTextureCacheクラスのaddImage(const char *fileName)が呼ばれているため、
キャッシュされ、二回目以降の呼び出しは高速になる。


以上でぇぇぇぇぇす。

0 件のコメント: