cocos2dx 3.x 自学笔记 <三> cocos2dx 2.x 3.x 内存管理机制
2014-11-12 21:05
295 查看
转载请注明来自 _鞋男blog:/article/7618210.html
仍然是2.x 与 3.x 的对比
cocos2dx 2.x:
当我们创建一个精灵的时候,都会调用精灵对象的autorelease(),
敢说CCSprite不是CCObject的派生类!!!
有个CCPoolManager全局对象,把精灵对象加了进去
形参为CCObject* ,这就已经不用管对象是不是精灵了,我们只需要记得是个CCObject对象,至于多肽神马的有RTTI机制搞定了。
继续跟进:
CCAssert(m_pCurReleasePool, "current auto release pool should not be null");
return m_pCurReleasePool;
}
这里简单说明下,
以上代码可以看出我们创建的对象被加入到一个CCArray中的一个CCAutoreleasePool中,看这
以上基本把retain() ,release() ,autorelease()讲了个遍。
接下来将引擎如果管理CCAutoreleasePool的:
若连续两次autorelease会怎样?
cocos2dx 2.x.x 内存管理我也只了解这么多,欢迎留言探讨。
原创BLOG : _鞋男 /article/7618210.html
cocos2dx 3.x 内存管理机制与2.x 差不多,数据结构改变了,用vector<> 代替了 CCArray ,在addObject是无需retain 再release,实现方便了不少
仍然是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 : _鞋男 /article/7618210.html
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(),看起来清爽多了 ,简简单单
相关文章推荐
- cocos2dx 3.x 自学笔记 <一> :cocos2dx 3.X 中的回调
- cocos2dx 3.x 自学笔记 <二> cocos2dx 中注册触摸事件touchEvent 2.x 与 3.x
- LDAP学习笔记<三>深入管理openLDAP
- cocos2dx 自学笔记 <四> 瓦片地图 Tiled Map 学习
- 进程控制理论<三>----共享内存
- <center>oc内存管理机制<:center>
- <Effective C++: 资源管理> 笔记
- Java笔记1 Java编程基础<2>循环语句、函数(重载)、变量和数组的内存结构
- 简易printf打印实现,占用内存非常小------<嵌入式开发自学笔记>
- 全面介绍Windows内存管理机制<转载>
- cocos2dx lua学习笔记 <一> quick 3.5把自定义C++类绑定到lua
- <<Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法>>笔记-内存管理
- quick-cocos2d-x的热更新机制实现<三>Updater(C++)
- 【javascript笔记】 函数内部属性以及方法<三>
- hadoop学习笔记<三>----HDFS
- Windows学习笔记5——窗口与消息<三>
- 黑马程序员自学笔记 Java基础<五>---> 多线程
- 【Linux基础笔记】一些感觉重要的基本命令<三>
- cocos2dx内存管理机制学习笔记,源码分析
- 服务器开发之内存<一> 小片内存的管理