coco2dx内存管理(源码版本:cocos2d-x-2.2.3)

深入的了解cocos2dx内存管理可以知道cocos2dx在这方面所做的动作,这样可以减少在开发的时候遇到的意料之外的错误。

cocos2dx的内存管理类名叫:CCobject。这个类用到的地方非常多,甚至可以说这个类是所有cocos2dx类的基类。虽然也有一些类没有从这个类继承内存管理功能,不过非常少。

CCObject类继承自CCCopying类,从CCCopying的名字来看主要是提供对象拷贝的重载,类的定义也证实了这一点。

class CC_DLL CCCopying
{
public:
    virtual CCObject* copyWithZone(CCZone* pZone);
};

cocos2dx的内存管理分为2种,一种是基于引用计数的判断删除对象,一种是每绘制一帧后来进行自动释放对象。另外,cocos2dx的内存管理并不像boost的智能指针那样,在对象离开作用域之后自动删除内存(引用计数),在cocos2dx里边如果要删除对象还需要显示的调用CCObject::release()函数。

第一种内存管理主要是通过CCObject对象的两个函数来进行:retain()和release()。对象调用retain使得引用计数增加1(在创建的时候引用计数初始化为1),release使得对象引用计数减一,但不会立即删除内存,只有对象持有的引用计数等于0的时候才会删除对象。

CCObject::CCObject(void)
: m_nLuaID(0)
, m_uReference(1) // when the object is created, the reference count of it is 1
, m_uAutoReleaseCount(0)
{
    static unsigned int uObjectCount = 0;

    m_uID = ++uObjectCount;
}
void CCObject::release(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");
    --m_uReference;

    if (m_uReference == 0)
    {
        delete this;
    }
}

void CCObject::retain(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");

    ++m_uReference;
}

第二种内存管理初看略显复杂,但是理清楚之后却觉得简单了。还记得在mainloop()函数中,有这么一行代码:

CCPoolManager::sharedPoolManager()->pop();    

这一行的作用是release掉当前栈顶内存池里边 所有的对象,而且需要注意的是在函数里边只是调用release()函数而已并没有直接delete掉对象。贴一下pop函数的代码以及注释。这里有一个意外的情况,那就是如果在对象池释放对象之前对象被删除了怎么办?会不会造成野指针呢?答案是不会,在CCObject函数里边会检查m_uAutoReleaseCount变量,如果大于0那么就从对象池里边删除掉该对象。

CCObject::~CCObject(void)
{
    // if the object is managed, we should remove it
    // from pool manager
    if (m_uAutoReleaseCount > 0)
    {
        CCPoolManager::sharedPoolManager()->removeObject(this);
    }

    // if the object is referenced by Lua engine, remove it
    if (m_nLuaID)
    {
        CCScriptEngineManager::sharedManager()->getScriptEngine()->removeScriptObjectByCCObject(this);
    }
    else
    {
        CCScriptEngineProtocol* pEngine = CCScriptEngineManager::sharedManager()->getScriptEngine();
        if (pEngine != NULL && pEngine->getScriptType() == kScriptTypeJavascript)
        {
            pEngine->removeScriptObjectByCCObject(this);
        }
    }
}
贴一下CCPoolManager::sharedPoolManager()->pop();  的代码

void CCPoolManager::pop()
{
	//当前栈顶内存池是否有分配。
    if (! m_pCurReleasePool)
    {
        return;
    }
	//取得栈里边所有内存池数量。
     int nCount = m_pReleasePoolStack->count();
	 //释放掉当前栈顶内存池内存,调用release(),并没有直接delete this。
    m_pCurReleasePool->clear();
 
      if(nCount > 1)
      {
        m_pReleasePoolStack->removeObjectAtIndex(nCount-1);

//         if(nCount > 1)
//         {
//             m_pCurReleasePool = m_pReleasePoolStack->objectAtIndex(nCount - 2);
//             return;
//         }
        m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);
    }
	  
    /*m_pCurReleasePool = NULL;*/
}

下面是m_pCurReleasePool->clear()源码及注释

void CCAutoreleasePool::clear()
{
	//内存池对象数组。
    if(m_pManagedObjectArray->count() > 0)
    {
        //CCAutoreleasePool* pReleasePool;
#ifdef _DEBUG
        int nIndex = m_pManagedObjectArray->count() - 1;
#endif

        CCObject* pObj = NULL;
		//循环释放掉autoreleasecount标记。
        CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj)
        {
            if(!pObj)
                break;

            --(pObj->m_uAutoReleaseCount);
            //(*it)->release();
            //delete (*it);
#ifdef _DEBUG
            nIndex--;
#endif
        }
		//释放掉所有保存的对象。调用release()
        m_pManagedObjectArray->removeAllObjects();
    }
}
看一下 m_pManagedObjectArray->removeAllObjects()里边发生了什么。
void CCArray::removeAllObjects()
{
    ccArrayRemoveAllObjects(data);
}
/** Removes all objects from arr */
void ccArrayRemoveAllObjects(ccArray *arr)
{
	while( arr->num > 0 )
    {
		(arr->arr[--arr->num])->release();
    }
}

如果需要将对象放到内存池进行自动释放管理只需要调用CCObject::autorelease()就可以了。

至此,cocos2dx的内存管理分析到这了,希望大家能有所收获^_^!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值