cococococos 2 d-xはon Enter、one Exit、引用カウントからメモリ漏れ問題を話します.

12507 ワード

////////////////////////////////////
//author:zhxfl
//ダテ  : 203.8.29
//email : [email protected]
//Adress:  http://www.cnblogs.com/zhxfl/p/3288510.html 
////////////////////////////////////
 
これを見る前に、まずone Enter、one Exitとコンストラクションを理解してください.
総じて言えば、順番は以下の通りです.
 
構造関数{}
one Enter{}
one Exit{}
構造関数{}
 
これを言う前に、実践の中で発生した問題について話します.この間プロジェクトの中でfixは二つのメモリ関連のバグを落としました.そしてこの二つの方法についていくつかの新しい理解があります.
 
1私たちが使っているcococos 2 d-xのバージョンはcocococos 2 d-1.0.1-x-002.0で、その時はまだCCListView.cppというリストコントロールがなかったので、プロジェクトグループは自分でこのコントロールを書きました.リストコントロールは写真や文字などの情報が必要であることを知っていますので、虚類と書かなければなりません.次のとおりです
 

struct IListItem:

{

    //how we draw this item

    virtual cocos2d::CCNode *createNode(float width) = 0;

    virtual ~IListItem() {}

};
View Code
 
対応するItemは、IListViewを引き継いでこのインターフェースを作成する必要があります.
 

class FightItem : public IListItem

{

public:



    FightItem(const DailyProperty &dp);

    ~FightItem();

    virtual cocos2d::CCNode *createNode(float width);

    virtual void onExit();

    void selected();

    void unselected();



    static FightItem *itemWithFight(const DailyProperty &dp);

    const DailyProperty &getDailyProperty()

    {

        return m_dp;

    }



private:

    cocos2d::CCNode *m_node;

};
View Code
 
このインターフェースを見終わったら、FightItem*item(以下はすべてitemでFightItemの例を指す)を申請したら、itemのリリースはdeleteを使うしかないです.もともとはdeleteを使っても大丈夫です.需要の変化につれて、私達はいくつかの高級な方法を使います.例えばFigthItemの中にあります.この時はCCCallFncを呼び出す必要があります.actionWithTargetはcalfunc_uselectorと似たような方法です.ここでFightItemにCCObjectを引き継いでcalfunc_uselectorを使うことができます.だからFightItemの声明は変更されました.
 

class FightItem : public IListItem, cocos2d::CCObject

{

public:



    FightItem(const DailyProperty &dp);

    ~FightItem();

    virtual cocos2d::CCNode *createNode(float width);

    virtual void onExit();

    void selected();

    void unselected();



    static FightItem *itemWithFight(const DailyProperty &dp);

    const DailyProperty &getDailyProperty()

    {

        return m_dp;

    }



private:

    cocos2d::CCNode *m_node;

    void change();

};
View Code
 
ここでメモリ管理が問題になりました.つまりreleaseとdeleteの混用の問題です.FightItemは今は参照カウントで管理しています.CCListViewの中ではdeleteでFightItemを解放しました.参照カウントはまだFightItemが解放されていないと思います.ここはdouble freeです.2回のエラーを解放しました.
 
ここでは、引用カウントを導入してメモリ管理をする場合、できるだけdeleteを混用しないようにしてください.他の人が混用を知らないと、このような問題が発生します.
もちろん、CCListViewにもFightItem*item;item->release()を採用しています.このようなリリースメカニズムは、問題が決裂しました.そして、次の問題が発生しました.
再び発生したのは漏洩問題です.
 
私達はFightItemの中でアニメーションを放送したいです.この時、私達は次のような方法を使いました.
 

CCScheduler::sharedScheduler()->scheduleSelector(

          schedule_selector(FightItem::showTimeDescription), this, 0.5f, false);
View Code
 
はい、今私たちのコンストラクションはこのように書きます.
 

FightItem::~FightItem()

{

    CCScheduler::sharedScheduler()->unscheduleSelector(

        schedule_selector(FightItem::showTimeDescription), this);

    if(m_node) m_node->release();

}
View Code
 
このように何の問題があるかは分かりませんが、偶然にもこのコンストラクションは実行されていないことが分かりました.本当に偶然です.このようなリークは確かに見つけにくいです.ですから、まずこの意識を立てることが重要です.プロジェクトコードが多くなるまで、プロジェクト全体を調査します.なぜ実行しないのかを分析します.
 
FightItem作成時count[参照カウント]は1で実行します.
CCScheduler:sharedScheduler()->scheduleSelector(
          schedule selector(FightItem:show TimeDescription)、this、0.5 f、false);
参照カウントは2で、CCListView参照カウントは3である(参照カウントが1の場合、システムによって直接解放される).CCSchedulerがFightItemを占有していることを説明する.元の削除プロセスに従って、CCListViewがitem-releaseを実行する().FightItem参照カウントは2となり、CCSchedulerによって占有されます.C++の仕組みでdeleteは実行されていません.FightItemも入っていません.
CCScheduler:sharedScheduler->unscheduleSelector
schedule selector(FightItem:ShowTimeDescription)、this);
関数は中に書いてありますが、実行する機会がないので、このようなitemは永遠にリリースする機会がありません.データベースの中のデッドロックのように聞こえます.
 
やっとテーマを書くことができます.その時は虚関数one Exitが必要です.

struct IListItem:public cocos2d::CCObject

{

    //how we draw this item

    virtual cocos2d::CCNode *createNode(float width) = 0;

    virtual ~IListItem() {}

    virtual void onExit() {}

};



FightItem::~FightItem()

{

    if(m_node) m_node->release();

}



void FightItem::onExit()

{

    CCScheduler::sharedScheduler()->unscheduleSelector(

        schedule_selector(FightItem::showTimeDescription), this);

}
View Code
CCListView実行item->release()はこのように変更されました.
item->オンスExit()
item->release();
one Exit()はCCSchedulerの引用をクリアし、CCListViewに続いてrelease()を実行します.この時は引用は0とカウントされ、システムはdeleteを実行します.この時~FightItem()が入ります.
 
この時点で最終的な結論が得られます.one Enter、one Exitは引用カウント機構に合わせて存在します.全体的に言えば、すべての製造コストの対象が他の対象に引用される操作は、one Enterの中に置いてあります.本オブジェクトを除いて他の対象に引用される操作は全部OnExitの中に入れます.
 
ですから、私たちは普通次のような仕様で書いています.メモリ漏れが少ないです.

void CCImageBtn::onEnter()

{

    CCNode::onEnter();

    CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, m_touchPriority, true);

}



void CCImageBtn::onExit()

{

    CCTouchDispatcher::sharedDispatcher()->removeDelegate(this);

    CCNode::onExit();

}
View Code