[cocos2dx][CocosBuilder] TextureCacheとCocosBuilderのトラップコンボ

 連日cocos2dxのトラップに引っかかってばかりですが、本日も盛大にハマりました。正確には本日まで、ですが。
 本日ご紹介するのは、TextureCache(CCTextureCache)とCocosBuilderで発生する問題です。両方がバグっているというわけではなく、CocosBuilderのバグがTextureCacheの仕様によって増幅され襲いかかるものです。CocosBuilderを使っている方はもれなくこのトラップに引っかかる可能性があるので注意が必要です。

発生した問題

 ゲーム中にそこそこ大きいアセットを読み込むことになったので、ゲーム開始時に読み込む→ゲーム終了時に解放、の流れが必要になりました。そこで、SpriteFrameCache::addSpriteFramesWithFileでplistを読み、シーン終了後にremoveSpriteFramesFromFileしたのですが…解放されない!にも関わらず、再度ゲームを開始するとアセットを読み込み始めました。ゲームを開始する度にガンガンメモリを食い続け…そのままお亡くなりになりました。

TextureCacheのremove〜系メソッドの仕様

 TextureCacheにはremoveで始まるメソッドがいくつかあります。SpriteFrameCacheも同様です。以下にその例を挙げます。

  • removeAllTextures
    • 全てのテクスチャを解放します。
  • removeUnusedTextures
    • 使用されていないテクスチャを解放します。
  • removeTexture
    • 指定されたテクスチャを解放します。
  • removeTextureForKey
    • 指定されたテクスチャ(引数はテクスチャ名)を解放します。
 これらのメソッドは、読んで字のごとく内部に保持しているテクスチャを解放するメソッドです。しかし、これらのメソッドを呼ぶ際には注意が必要で、テクスチャが参照されている場合はテクスチャリストからテクスチャへのポインタが消えるだけで、テクスチャそのものは解放されません!!
 このクソ仕様は何なんでしょう。参照されているから消さない、それは正しいと思うのですが、なんでリストから消すんでしょうか…参照しているスプライトとかがなくなったタイミングで解放されるようにしたかったんでしょうかね…

 そんなわけで、テクスチャキャッシュからテクスチャを解放する際は、解放したいテクスチャの参照カウントが1になっているかどうか確認しましょう。なんか解放されないなーって時はこれが原因かと思います。

CocosBuilder(CCBReader)のバグ

 CocosBuilderはそもそもバグだらけの開発ツールなので今更何が起こっても驚きませんが、驚かないにしてもストレスは溜まります。
 今回の致命的なバグは、CocosBuilderというよりCCBReaderのバグで、readNodeGraphFromFileで生成したノードの参照カウントが1増えているというものです。つまり、明示的にreleaseしてやらないと一生メモリ上で生き続けます。なるほど、これはひどい。
 対策として、addChildした際にreleaseを呼んでしまうのが楽だと思います。

この2つが混ざり合って…

 最初の事件が起こるわけです。シーンが消えたにも関わらずCocosBuilderで生成したレイヤーが解放されず、そいつが握っていたテクスチャも道連れにメモリリークしてしまった、な感じです。
 このメドローア級のバグですが、CocosBuilderを使っていれば誰でも瀕死のダメージを受けることになると思います。対策はしっかり打ちましょう。

 なお、この不具合はcocos2dx 2.2.2 + CocosBuilder 3 alpha 5で確認しています。

0 件のコメント :

コメントを投稿