Cocos2d-x:メモリリークを回避するためのいくつかのヒント

Cocos2d-xは「エンジン」、またはむしろ、HTML 5だけでなくiOS、Android、Windows Phone、Windowsなどのオペレーティングシステム用のグラフィカルアプリケーションの開発を大幅に簡素化するクラスのセットです。cocos2d-iphone、cocos2d- xはC ++開発を伴うため、非常に普遍的です。 C ++で書く人は、メモリの割り当てと解放の責任はすべてプログラマにあることを知っています。 しかし、cocos2d-xの開発者はこれを大事にして、すばらしいエンジンにオブジェクトプールを組み込みました。これにはスマートポインター、つまりスマートポインターの使用が含まれます。 スマートポインターには、そのクライアントのカウンターが含まれています。カウンターがゼロの場合、オブジェクトに割り当てられたメモリはクリアされます。 この記事では、メモリーリークを回避するために、cocos2d-xでオブジェクトを正しく作成および削除する方法を示します。 すべてのcocos2d-xクラスオブジェクトはスマートポインターです。 エンジンのクラスライブラリの階層内の開始リンクである親CCObjectからこの機能を受け取りました。

通常、ヒープにオブジェクトを作成するプログラマーは、次のコードを記述します。
CMyObject* pObject = new CMyObject(); // ,   CMyObject —    . 

この場合、CMyObjectはメモリ内に作成され、それへのポインターはpObject変数に配置されます。 pObjectが不要になったら、メモリを返す必要があります。
 delete pObject; 

通常、多くのオブジェクトは、1つのアプリケーションモジュールではなく、作業中のプロジェクトで作成されることが多く、最後にそれらがすべて削除されるようにする必要があります。そうしないと、メモリリークが発生します。 そのような迷惑を避けるために、cocos2d-xはオープンな静的関数を使用してオブジェクトを作成します。 特にプログラマがエンジンクラスの機能を拡張する場合、メモリリークを回避するためにこのルールを順守する必要があります。
cocos2d-xでスプライトを作成する例を考えてみましょう。
 ... CCSprite* pSprite = CCSprite::create(«spritename.png»); ... 

create-静的関数-オブジェクトを作成するCCSpriteクラスのメンバー。 この関数のコードを見てください:
 CCSprite* CCSprite::create(const char *pszFileName) { CCSprite *pobSprite = new CCSprite(); if (pobSprite && pobSprite->initWithFile(pszFileName)) { pobSprite->autorelease(); return pobSprite; } CC_SAFE_DELETE(pobSprite); return NULL; } 

まず、オブジェクトを作成し、コードを使用して初期化します。
 pobSprite->autorelease(); 

プールに追加します。 初期化が成功した場合、CCSpriteへのポインターを返します。そうでない場合、CC_SAFE_DELETEはpobSpriteを削除します。
この関数を実行した後、pSpriteのm_uReferenceは1になり、プールはエンジンの各クロックサイクルで更新されるため、ローカル関数を終了するまで存続します。 ここで注意する必要があります:クラスの再配布でpSpriteがグローバルである場合、それはガベージを指します。 これを防ぐには、作成したオブジェクトを使用する必要があります。 たとえば、レイヤーにスプライトを追加します。
 pLayer->addChild(pSprite); 
、または配列へ
 pArray->addObject(pSprite); 
pSpriteが追加されるたびに、そのm_uReferenceは必ずしも1ずつ増加するわけではありません。これはエンジンの特定の実装であり、その内部でワークリスト、配列などはm_uReferenceにも影響します。 そして、pSpriteが削除されるたびに、そのm_uReferenceはそれに応じて減少します。 次のメソッドを使用して、m_uReferenceを自分で増減できます。
 pSprite->retain(); // m_uReference +=1 pStrite->release(); // m_uReference -=1 

これらのメソッドを慎重に使用してください。各retain()はrelease()の呼び出しに対応する必要があります。 そうしないと、オブジェクトがメモリに残り、メモリリークが発生します。
次に、クラスの拡張について説明します。 ほぼCCSpriteに似ているが、追加機能を備えたオブジェクトが必要だとしましょう。
プロジェクトから派生クラスを宣言する例を次に示します。
 class TABonus:public CCSprite { TABonusType mType; TABonus(b2World* world, float pX, float pY,TABonusType type); virtual bool init(); public: float pBegX, pBegY; virtual ~TABonus(); static TABonus* create(b2World* world, float pX, float pY,TABonusType type); inline TABonusType getType() {return mType;} void update(float pSecondElapsed); }; 

コンストラクタは閉じたセクションで宣言されていることに注意してください-これは、オブジェクトの直接作成が禁止されていることを意味します。 これを行うには、静的関数createがクラスで宣言されます。
機能コードを見てみましょう。
 TABonus* TABonus::create(b2World* world, float pX, float pY,TABonusType type) { TABonus* pRet = new TABonus(world,pX,pY,type); if (pRet->init()) { pRet->autorelease(); return pRet; } CC_SAFE_DELETE(pRet); return NULL; } 

これは、以前に検討したものに似ています。 TABonusを作成するには、次のコードを使用する必要があります。
 TABonus* pBonus = TABonus::create(world,pX,pY, btCoins);// pBonus ->m_uReference == 0 pLayer->addChild(pBonus); //pBonus->m_uReference>0 


結論:

-静的関数を使用するため、new演算子を使用してオブジェクトを直接作成しないようにしてください。 また、派生クラスから継承する場合は、静的関数を作成する必要があります。
-オブジェクトを削除するには、追加されたすべてのコンテナからオブジェクトを削除する必要があります。m_uReferenceはゼロにリセットされ、オブジェクトに割り当てられたメモリがヒープに返されます。 たとえば、レイヤーからpSpriteを削除します。
 pLayer->removeChild(pSprite, true); 

または配列から:
 pArray->removeObject(pSprite); 

-静的関数で作成されたオブジェクトにはdeleteを使用しないでください。オブジェクトがもう存在しないことをあなた以外の誰も知らないためです。
-オブジェクトを存続させるには、コンテナに追加するか、retain()を呼び出して、m_uReferenceを増やす必要があります。

ルールを守って勝ちましょう。

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

Source: https://habr.com/ru/post/J205568/


All Articles