cocos2d-x自动内存管理

cocos2d-x管理内存主要是通过如下三个函数来管理:
1、retain
2、release
3、autorelease

其中:
autorelease函数是将对象加入到cocos2d-x的自动内存释放池中,然后在程序mainloop中每次循环中都会通过调用自动内存释放池的pop函数来释放管理池中引用次数只有1的对象。

调用类的create函数创建对象,然后加入到autorelease中。
注意如果创建一个对象,并将他加入到内存池中之后,对象的引用次数仍然为1,如果不对对象做任何其他操作,那么将会在下一帧更新的mainloop中被内存池自动释放掉。

对于一个加入到自动释放池中的对象,如果用户还希望能够继续使用该对象,那么就必须手动调用retain函数,然后在不是用的时候调用release函数。否则就会被当作一个创建期对象在自动释放池中被delete。

当一个对象被加入另外的对象之中时,相应的add操作会调用retain,从另外的对象中移除的时候,调用release操作。

cocos2d-x中将对象分为两类:
创建期对象:调用create方法生成之后。如果不对其进行其他操作,在pop函数中将会被当成创建期对象删除。
使用期对象:当执行了pop函数从自动释放池中移除之后,如果这个时候对象没有被删除,那么进入使用期。

个人感觉这种内存释放机制并不是很科学.
使用这种方式唯一的好处就是用户不用在考虑什么时候调用delete函数了,因为不管哪种方式都会自动帮你调用delete,但是也必须保证使用对象的时候正确调用retain和release函数,否则仍然会导致内存泄漏。

说了这么多,对于程序员来说还是代码最直接,下面来看看自动内存管理到底对对象干了什么。

1、autorelease函数
CCObject* CCObject::autorelease(void)
{
    CCPoolManager::sharedPoolManager()->addObject(this);
    return this;
}
当对象创建之后调用autorelease函数,这个时候对象的引用计数为1。
这个函数是将对象加入内存池中。
CCPoolManager::sharedPoolManager()是一个单例设计模式,保证整个应用程序中只存在一个CCPoolManager的实例。
CCPoolManager* CCPoolManager::sharedPoolManager()
{
    if (s_pPoolManager == NULL)
    {
        s_pPoolManager = new CCPoolManager();
    }
    return s_pPoolManager;
}



void CCPoolManager::addObject(CCObject* pObject)
{
    getCurReleasePool()->addObject(pObject);
}
getCurRelesePool函数用于获取CCPoolManager中的可用的自动释放内存池。
CCAutoreleasePool* CCPoolManager::getCurReleasePool()
{
    if(!m_pCurReleasePool)
    {
        push();
    }

    CCAssert(m_pCurReleasePool, "current auto release pool should not be null");

    return m_pCurReleasePool;
}
如果有个内存池对象就直接返回,没有的话就调用push函数来创建一个CCAutoreleasePool对象,并加入CCPoolManager中。
void CCPoolManager::push()
{
    CCAutoreleasePool* pPool = new CCAutoreleasePool();       //ref = 1
    m_pCurReleasePool = pPool;

    m_pReleasePoolStack->addObject(pPool);                   //ref = 2

    pPool->release();                                       //ref = 1
}
当得到CCAutoreleasePool对象之后调用其addObject函数将对象加入自动释放内存池。
void CCAutoreleasePool::addObject(CCObject* pObject)
{
    m_pManagedObjectArray->addObject(pObject);//ref = 2

    CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1");
    ++(pObject->m_uAutoReleaseCount); //m_uAutoReleaseCount = 1,表示对象被自动释放内存池管理。
    pObject->release(); //ref = 1// no ref count, in this case autorelease pool added.
}
数组的添加操作代码这里就不讲述了,有兴趣的读者可以自行查阅。
说道这里对象就已经被加入自动释放内存池了,那么什么时候被删除了,请看下面的代码。
在程序的主循环中有这样一句话CCDirector::sharedDirector()->mainLoop();具体代码在对应平台的CCApplication文件的run函数中。
下面我们进入mainLoop函数。

void CCDisplayLinkDirector::mainLoop(void)
{
    if (m_bPurgeDirecotorInNextLoop)
    {
        m_bPurgeDirecotorInNextLoop = false;
        purgeDirector();
    }
    else if (! m_bInvalid)
     {
         drawScene();
     
         // release the objects
         CCPoolManager::sharedPoolManager()->pop();        
     }
}
第一个if语句与自动释放内存池无关,主要用于程序退出的时候做清理工作。主要看pop函数。
void CCPoolManager::pop()
{
    if (! m_pCurReleasePool) //如果manager中没有自动释放池,直接返回。
    {
        return;
    }

     int nCount = m_pReleasePoolStack->count(); //获取自动释放池个数。

    m_pCurReleasePool->clear(); //执行清理工作。
 
      if(nCount > 1) //如果自动释放大于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;*/
}
下面来看clear函数,这个函数用于执行清理工作。
void CCAutoreleasePool::clear()
{
    if(m_pManagedObjectArray->count() > 0)
    {
        //CCAutoreleasePool* pReleasePool;
#ifdef _DEBUG
        int nIndex = m_pManagedObjectArray->count() - 1;
#endif

        CCObject* pObj = NULL;
        CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj)
        {
            if(!pObj)
                break;

            --(pObj->m_uAutoReleaseCount); //m_uAutoReleaseCount=0前提是子调用了一次autorelease函数,表示对象不再处于自动释放池管理范围内。
            //(*it)->release();
            //delete (*it);
#ifdef _DEBUG
            nIndex--;
#endif
        }

        m_pManagedObjectArray->removeAllObjects();//将对象从array内移除,这里会调用对象的release函数。
    }
}
因为之前说过在创建对象、调用autorelease函数之后对象的引用计数仍然为1,所以如果对象没有调用retain函数,那么对象将会在release函数中被删除,从而达到自动内存管理的目的。
最后看看retain和release函数干了什么。
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;
}



这两个函数一个用于增加引用计数,一个用于减小引用计数,当引用计数为0,就删除对象。
写的有点多,总之在使用cocos2d-x的时候,记得如果需要持有一个对象就要调用retain函数,不再使用的时候就调用release函数。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值