转载请注明来自 _鞋男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, 0, 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(),release(),看起来清爽多了 ,简简单单