Cocos2d-x游戏开发实例详解6:自动释放池
本系列将结合本人的游戏开发实例,详细讲解Cocos2d-x。在本篇文章中,我们将深入探讨内存的自动释放池。在上一篇文章中,我们学习了引用计数和自动释放的大致流程,但略过了自动释放池的相关内容,下面将对其进行详细阐述。
1. CCObject
的 autorelease
函数
前面提到了 CCObject
的 autorelease
函数,其代码如下:
CCObject* CCObject::autorelease(void)
{
CCPoolManager::sharedPoolManager()->addObject(this);
return this;
}
这里的 sharedPoolManager()
函数表明 CCPoolManager
是一个单例类。在Cocos2d-x中,大量使用了单例模式,每个单例类都有一个明显的标志,即其实例获取函数,从命名规则上看,通常都是 sharedxxx()
的形式。
2. 跟进 addObject
函数
接下来,我们跟进 addObject
函数:
void CCPoolManager::addObject(CCObject* pObject)
{
getCurReleasePool()->addObject(pObject);
}
这就涉及到了 CCPoolManager
类,下面我们来详细分析这个类:
class CC_DLL CCPoolManager
{
CCArray* m_pReleasePoolStack;
CCAutoreleasePool* m_pCurReleasePool;
CCAutoreleasePool* getCurReleasePool();
public:
CCPoolManager();
~CCPoolManager();
void finalize();
void push();
void pop();
void removeObject(CCObject* pObject);
void addObject(CCObject* pObject);
static CCPoolManager* sharedPoolManager();
static void purgePoolManager();
friend class CCAutoreleasePool;
};
从上述代码可以看出,CCPoolManager
类维护了一个自动释放池 CCAutoreleasePool
,同时还有一个 CCArray
变量,它是一个栈结构,用于管理自动释放池。
3. 具体实现分析
3.1 CCAutoreleasePool
类的实现
#include "CCAutoreleasePool.h"
#include "ccMacros.h"
NS_CC_BEGIN
// 自动释放池管理员实例
static CCPoolManager* s_pPoolManager = NULL;
CCAutoreleasePool::CCAutoreleasePool(void)
{
m_pManagedObjectArray = new CCArray(); // 自动释放的对象放在这个Array里面
m_pManagedObjectArray->init();
}
CCAutoreleasePool::~CCAutoreleasePool(void)
{
CC_SAFE_DELETE(m_pManagedObjectArray);
}
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.
}
void CCAutoreleasePool::removeObject(CCObject* pObject)
{
for (unsigned int i = 0; i < pObject->m_uAutoReleaseCount; ++i)
{
m_pManagedObjectArray->removeObject(pObject, false);
}
}
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);
//(*it)->release();
//delete (*it);
#ifdef _DEBUG
nIndex--;
#endif
}
m_pManagedObjectArray->removeAllObjects();
}
}
在 CCAutoreleasePool
类中,addObject
函数将对象添加到 m_pManagedObjectArray
中,并对对象的引用计数进行相应的操作;removeObject
函数用于从管理数组中移除对象;clear
函数则用于清空管理数组中的所有对象。
3.2 CCPoolManager
类的实现
CCPoolManager* CCPoolManager::sharedPoolManager() // 获取管理员实例
{
if (s_pPoolManager == NULL)
{
s_pPoolManager = new CCPoolManager(); // 如果没有实例,调构造函数
}
return s_pPoolManager;
}
void CCPoolManager::purgePoolManager()
{
CC_SAFE_DELETE(s_pPoolManager);
}
CCPoolManager::CCPoolManager()
{
m_pReleasePoolStack = new CCArray(); // 栈结构,管理自动释放池
m_pReleasePoolStack->init();
m_pCurReleasePool = 0;
}
CCPoolManager::~CCPoolManager()
{
finalize();
// we only release the last autorelease pool here
m_pCurReleasePool = 0;
m_pReleasePoolStack->removeObjectAtIndex(0);
CC_SAFE_DELETE(m_pReleasePoolStack);
}
void CCPoolManager::finalize()
{
if(m_pReleasePoolStack->count() > 0)
{
//CCAutoreleasePool* pReleasePool;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pReleasePoolStack, pObj) // 遍历对象池栈,清空所有对象池
{
if(!pObj)
break;
CCAutoreleasePool* pPool = (CCAutoreleasePool*)pObj;
pPool->clear();
}
}
}
void CCPoolManager::push() // 管理员的push方法,将对象池栈压栈。当前对象池为NULL时才调用push函数
{
CCAutoreleasePool* pPool = new CCAutoreleasePool(); // ref = 1
m_pCurReleasePool = pPool;
m_pReleasePoolStack->addObject(pPool); // ref = 2
pPool->release(); // ref = 1
}
void CCPoolManager::pop() // 管理员的pop方法,将对象池栈弹栈,其实就是释放对象
{
if (! m_pCurReleasePool)
{
return;
}
int nCount = m_pReleasePoolStack->count();
m_pCurReleasePool->clear();
if(nCount > 1)
{
m_pReleasePoolStack->removeObjectAtIndex(nCount - 1);
m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);
}
/*m_pCurReleasePool = NULL;*/
}
void CCPoolManager::removeObject(CCObject* pObject)
{
CCAssert(m_pCurReleasePool, "current auto release pool should not be null");
m_pCurReleasePool->removeObject(pObject);
}
void CCPoolManager::addObject(CCObject* pObject)
{
getCurReleasePool()->addObject(pObject); // 将对象添加到当前的对象池
}
CCAutoreleasePool* CCPoolManager::getCurReleasePool() // 获取当前对象池
{
if(!m_pCurReleasePool)
{
push(); // 对象池由一个栈维护。当前对象池为空,则push一下,push函数会new一个对象池,然后添加到栈里
}
CCAssert(m_pCurReleasePool, "current auto release pool should not be null");
return m_pCurReleasePool;
}
NS_CC_END
在 CCPoolManager
类中,sharedPoolManager
函数用于获取单例实例;push
函数用于将新的自动释放池压入栈中;pop
函数用于将栈顶的自动释放池弹出并释放其中的对象;addObject
函数将对象添加到当前的自动释放池中;getCurReleasePool
函数用于获取当前的自动释放池,如果当前池为空,则创建一个新的池并添加到栈中。
4. 后续展望
关于一个对象添加到自动释放池后在什么时机被释放,本文暂不详细阐述,后续有机会将进行深入分析。
通过以上对Cocos2d-x自动释放池的详细分析,我们可以更好地理解其内存管理机制,从而在游戏开发中更加合理地使用自动释放池,避免内存泄漏等问题。