现在的位置: 首页 > 综合 > 正文

工程使用cocosBuilder后内存相关管理总结

2018年05月27日 ⁄ 综合 ⁄ 共 2660字 ⁄ 字号 评论关闭

最近几天把查了项目的内存泄漏问题,发现了些之前没想到问题,主要是引用后cocosBuilder导致的问题。

首先说下cocos2dx里面,基本的一些内存管理原则

1.每个CCObject对象在创建时 (eg: new CCObject ()), 它的引用计数为1,
2.它是autorelease的 (大部分情况下是这样的) 会在这一帧的结束时,被autorelease掉
3.CCNode对象的析构函数,会递归调用它所有孩子及子孩子的release, 对应在addChild时它们被调用的retain ()

4.所有手动调用retain () 的对象 (比如要保持住一个CCObject对象, 而它又不用被加到场景中去), 都要对应显示调用release ()

正常来讲,只要注意以上几点,项目中是不会出现内存问题,但在引用cocosBuilder后.会出现一些意想不到的事.
首先CCB_MEMBERVARIABLEASSIGNER_GLUE(...).

#define CCB_MEMBERVARIABLEASSIGNER_GLUE(TARGET, MEMBERVARIABLENAME, MEMBERVARIABLETYPE, MEMBERVARIABLE) \
    if (pTarget == TARGET && 0 == strcmp(pMemberVariableName, (MEMBERVARIABLENAME))) { \
        MEMBERVARIABLETYPE pOldVar = MEMBERVARIABLE; \
        MEMBERVARIABLE = dynamic_cast<MEMBERVARIABLETYPE>(pNode); \
        CC_ASSERT(MEMBERVARIABLE); \
        if (pOldVar != MEMBERVARIABLE) { \
            CC_SAFE_RELEASE(pOldVar); \
            MEMBERVARIABLE->retain(); \
        } \
        return true; \
    }

用它来把ccb中的对象绑定到逻辑对象上时, 这个宏会把要绑定对象执行一次retain ().它是没有对应执行的release (), 这里如果不手工处理一下,会发现CCB里大量对象,在场景移除时,没有被解构
解决方法 1.在ccb资源的customClass的析构函数里, 对所以需要绑定的对象,执行一下release ()  eg:CC_SAFE_RELEASE_NULL (m_object).

    LoginShow_CCB()
    :CCLayer()

        ,m_menu(0)
        ,m_menuItem_exchangeUser(0)
        ,m_menuItem_exchangeServer(0)
        ,m_menuItem_enterGame(0)
        ,m_menuItem_binding(0)
        ,m_menuItem_reLogin(0)
        ,m_labelUserEmail(0)
        ,m_labelTip_email(0)
        ,m_labelServerName(0)
        ,m_labelTip_server(0)
        ,m_labelBundleVersion(0)
{}
virtual ~ LoginShow_CCB(){
//	CC_SAFE_RELEASE_NULL(m_menu);
//	CC_SAFE_RELEASE_NULL(m_menuItem_exchangeUser);
//	CC_SAFE_RELEASE_NULL(m_menuItem_exchangeServer);
//	CC_SAFE_RELEASE_NULL(m_menuItem_enterGame);
//	CC_SAFE_RELEASE_NULL(m_menuItem_binding);
//	CC_SAFE_RELEASE_NULL(m_menuItem_reLogin);
//	CC_SAFE_RELEASE_NULL(m_labelUserEmail);
//	CC_SAFE_RELEASE_NULL(m_labelTip_email);
//	CC_SAFE_RELEASE_NULL(m_labelServerName);
//	CC_SAFE_RELEASE_NULL(m_labelTip_server);
//	CC_SAFE_RELEASE_NULL(m_labelBundleVersion);
}

这里适合的情况是, 所有的绑定对象没有parent_child的所属关系.如果存在的话,和就上面提及到的第3条冲突了.有些结点就会重复release (),导致crash. 在C++里泄漏和crash只有一步之遥

解决方法 2.直接把宏里面的MEMBERVARIABLE->retain() 这句去掉,这种方式,暂时没发现问题

再一点,CCBAnimationManager::setAnimationCompletedCallback
如果需要在ccb的某一动作完成时,回调一个自定义方法,就会用到上面这句,这里也有一个坑,

void CCBAnimationManager::setAnimationCompletedCallback(CCObject *target, SEL_CallFunc callbackFunc) {
    if (target)
    {
        target->retain();
    }

    if (mTarget)
    {
        mTarget->release();
    }

    mTarget = target;
    mAnimationCompleteCallbackFunc = callbackFunc;
}

它个方法也会把CustomClass给retain (), 不注意的放,会有泄漏产生
解决方法 1. 在自定义的callBackFunc方法里,调用一下setAnimationCompletedCallback (NULL, NULL), 这种方式,要求每个callbackFunc都要记得写这句,(最后一个被回调的有用,但你不知道哪个最后调,所有都写最安全)
解决方法 2. 在customClass重写onExit (), 方法里写上这个setAnimationCompletedCallback (NULL, NULL), onExit方法千万别忘了写父类onExit eg: Parent::onExit, 不然有Touch注册的话,又是泄漏

另外,还有梅总之前发现的CCBReader对象,因为和customClass和循环依赖的问题, 要手动release掉.

关于CCBAnimationManager, 还有没有其它坑 (感觉还有,可能关系不大),有时间再研究一下,春哥要求赶紧总结下,以备方便他人

抱歉!评论已关闭.