转载请注明来自 _鞋男blog:http://blog.csdn.net/wushao126/article/details/41050605
仍然是2.x与 3.x的对比
cocos2dx 2.x:
当我们创建一个精灵的时候,都会调用精灵对象的autorelease(),
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; }当创建一个精灵对象的时候,
CCSprite* sprite = CCSprite::create(s_pPathGrossini); CCLog("sprite->retainCount()=%d",sprite->retainCount());//output:sprite->retainCount()=1 addChild(sprite,kTagSprite); CCLog("sprite->retainCount()=%d",sprite->retainCount());//output:sprite->retainCount()=2跟踪
pobSprite->autorelease();跳转到了
CCObject* CCObject::autorelease(void) { CCPoolManager::sharedPoolManager()->addObject(this); return this; }
敢说CCSprite不是CCObject的派生类!!!
有个CCPoolManager全局对象,把精灵对象加了进去
void CCPoolManager::addObject(CCObject* pObject) { getCurReleasePool()->addObject(pObject); }
形参为CCObject* ,这就已经不用管对象是不是精灵了,我们只需要记得是个CCObject对象,至于多肽神马的有RTTI机制搞定了。
继续跟进:
void CCPoolManager::addObject(CCObject* pObject) { getCurReleasePool()->addObject(pObject); } CCAutoreleasePool* CCPoolManager::getCurReleasePool() { if(!m_pCurReleasePool) { push();<pre name="code" class="cpp"> //创建一个自动释放池 并加入到释放池栈中}
CCAssert(m_pCurReleasePool,"current auto release pool should not be null");
return m_pCurReleasePool;
}
这里简单说明下,
class CC_DLL CCPoolManager { CCArray* m_pReleasePoolStack; CCAutoreleasePool* m_pCurReleasePool; public: ... friend class CCAutoreleasePool; };
void CCPoolManager::push() { CCAutoreleasePool* pPool = new CCAutoreleasePool(); //ref = 1 m_pCurReleasePool = pPool; m_pReleasePoolStack->addObject(pPool); //ref = 2 pPool->release(); //ref = 1 }
以上代码可以看出我们创建的对象被加入到一个CCArray中的一个CCAutoreleasePool中,看这
void CCAutoreleasePool::addObject(CCObject* pObject) { m_pManagedObjectArray->addObject(pObject); CCAssert(pObject->m_uReference > 1,"reference count should be greater than 1"); ++(pObject->m_uAutoReleaseCount); pObject->release(); // no ref count,in this case autorelease pool added. }其实在CCAutoreleasePool里也维持一个CCArray,用来存放被加入的CCObject对象,m_uReference在CCObject构造器中被初始化为1,m_uAutoReleaseCount +1了,但是autoRelease的时候未被引用,所以会被release,m_uReference被减1为0,因为到0的时候,那对象岂不是挂了,看下面代码
void ccArrayAppendObject(ccArray *arr,CCObject* object) { CCAssert(object != NULL,"Invalid parameter!"); object->retain(); arr->arr[arr->num] = object; arr->num++; }这个全局函数式CCArray::addObject调用,在这里retain()了对象,m_uReference为2,但是我们没有引用,所以在这里release了下
void CCObject::release(void) { CCAssert(m_uReference > 0,"reference count should greater than 0"); --m_uReference; if (m_uReference == 0) { delete this; } }至于CCArray是什么机制,这个以后会讲到的
以上基本把retain(),release(),autorelease()讲了个遍。
接下来将引擎如果管理CCAutoreleasePool的:
int CCApplication::run(){ ... while(1){ ... if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart) { nLast.QuadPart = nNow.QuadPart; CCDirector::sharedDirector()->mainLoop();// } ... } }CCDirector游戏引擎的管理者,这里介绍mainLoop(),顾名思义,主循环,任何系统都有它的死循环,这个也不例外。进去看看:
void CCDisplayLinkDirector::mainLoop(void) { if (m_bPurgeDirecotorInNextLoop) { m_bPurgeDirecotorInNextLoop = false; purgeDirector(); } else if (! m_bInvalid) { drawScene(); // release the objects CCPoolManager::sharedPoolManager()->pop(); } }这个也没什么与内存有关的也就是pop(),且看pop():
void CCPoolManager::pop() { if (! m_pCurReleasePool) { return; } int nCount = m_pReleasePoolStack->count(); 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_pReleasePoolStack存放的是CCAutoreleasePool对象,是个CCArray*,如果把这个CCArray看成一个栈,就将栈顶弹出,addObject会调用retain(),同理,removeObject会调用一次release(),但凡栈内m_uReference==1的对象将会被释放掉,因为没有被引用。
若连续两次autorelease会怎样?
cocos2dx 2.x.x内存管理我也只了解这么多,欢迎留言探讨。
原创BLOG : _鞋男 http://blog.csdn.net/wushao126/article/details/41050605
cocos2dx 3.x内存管理机制与2.x差不多,数据结构改变了,用vector<>代替了CCArray,在addObject是无需retain再release,实现方便了不少
void DisplayLinkDirector::mainLoop() { if (_purgeDirectorInNextLoop) { _purgeDirectorInNextLoop = false; purgeDirector(); } else if (! _invalid) { drawScene(); // release the objects PoolManager::getInstance()->getCurrentPool()->clear(); } }
void AutoreleasePool::clear() { #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) _isClearing = true; #endif for (const auto &obj : _managedObjectArray) { obj->release(); } _managedObjectArray.clear(); #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) _isClearing = false; #endif }
void Ref::release() { CCASSERT(_referenceCount > 0,"reference count should greater than 0"); --_referenceCount; if (_referenceCount == 0) { #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) auto poolManager = PoolManager::getInstance(); if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this)) { CCASSERT(false,"The reference shouldn't be 0 because it is still in autorelease pool."); } #endif #if CC_USE_MEM_LEAK_DETECTION untrackRef(this); #endif delete this; } }上面三段代码是每帧PoolManager管理内存池的代码,对照着2.x的也不难理解。
Ref* Ref::autorelease() { PoolManager::getInstance()->getCurrentPool()->addObject(this); return this; }
void AutoreleasePool::addObject(Ref* object) { _managedObjectArray.push_back(object); }由于用的是STL,所以在这里没有个调用retain(),看起来清爽多了 ,简简单单