cocos2d-x 之 内存管理(5)

上一篇文件讲到了CCObject中实现的内存自动管理内存

下面介绍两个很重要的类,一个是内存池类 CCAutoReleasePool ,另一个类是内存池管理类 CCPoolManager

这两个类结合在一起使用.

先看一下CCAutoReleasePool类,这个类其实就是对 CCArray的一个封装,把需要自动释放的对象,都添加到此类的成员变量m_pManagedObjectArray中

CCAutoReleasePool类的定义如下.还是直接在注释中解释比较方便,直接看注释吧.

 //内存池,其实就是一个CCArray的封装
class CC_DLL CCAutoreleasePool : public CCObject
{ CCArray* m_pManagedObjectArray;
public:
CCAutoreleasePool(void);
~CCAutoreleasePool(void); //向内存池添加一个对象
void addObject(CCObject *pObject); //删除内存池中的pObject对象
void removeObject(CCObject *pObject); //清空内存池中所有的对象
void clear();
};
CCAutoreleasePool 类中主要就3个函数,addObject函数,向内存池中添加一个自动释放的对象的指针. removeObject函数,向内存中把pObject这个对象删除 
最后一个clear函数,把内存池中所有的对象都释放掉
此类需要结合CCPoolManager使用
再看下 CCAutoReleasePool 类的实现文件,看注释,代码如下
CCAutoreleasePool::CCAutoreleasePool(void)
{
m_pManagedObjectArray = new CCArray(); //新建一个内存池,其实就是一个数组,里面存放的元素都是需要自动释放的内存的对象
m_pManagedObjectArray->init(); //初始化内存池
} CCAutoreleasePool::~CCAutoreleasePool(void)
{
CC_SAFE_DELETE(m_pManagedObjectArray); //释放内存池
} void CCAutoreleasePool::addObject(CCObject* pObject)
{
m_pManagedObjectArray->addObject(pObject);//向内存池中添加一个对象pObject,引用计数加 1 CCAssert(pObject->m_uReference > , "reference count should be greater than 1");
++(pObject->m_uAutoReleaseCount); //自动释放内存的标识 ++ ,++后就大于0了,就表明此对象会自动释放内存,具体在哪释放,后面文章会介绍
pObject->release(); // 因为向内存池中添加对象的时候,引用计数已经加1了,所以再减1
} //释放对象pObject的内存
void CCAutoreleasePool::removeObject(CCObject* pObject)
{
//如果对象pObject的自动释放标识大于0,则将对象pObject从内存池中删除掉
for (unsigned int i = ; i < pObject->m_uAutoReleaseCount; ++i)
{
//将对象pObject从内存池中删除掉
m_pManagedObjectArray->removeObject(pObject, false);
}
} //清理内存池
void CCAutoreleasePool::clear()
{
//如果内存池中的元素个数大于0
if(m_pManagedObjectArray->count() > )
{
//CCAutoreleasePool* pReleasePool;
#ifdef _DEBUG
int nIndex = m_pManagedObjectArray->count() - ; //内存池中,也就是数组的最后一个元素的索引
#endif //下面是遍历数组,就是上次文章讲到的数组遍历的反序遍历,就是从尾部向头部的顺序进行遍历
//把内存池中所有的元素的自动释放标识都减1
CCObject* pObj = NULL;
CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj)
{
if(!pObj)
break; --(pObj->m_uAutoReleaseCount); //自动释放内存标识减1
//(*it)->release();
//delete (*it);
#ifdef _DEBUG
nIndex--; //最后一个元素的索引位置也跟着减1
#endif
} //删除内存池中所有的元素
m_pManagedObjectArray->removeAllObjects();
}
}

以上是CCAutoReleasePool类的所有源码的解析,通过解析可以看出,CCAutoReleasePool就是封装了一个CCArray的一个对象,用一个数组存放所有的自动释放内存的对象

这个类需要和 CCPoolManager在结合使用,CCPoolManager从名字可以知道,是内存池管理器.专门用来管理内存池的.

CCPoolManager使用一个CCArray来封装了一个栈结构,栈顶为数组的最后一个元素,栈底为第一个元素.栈中所有的元素其实就是一个内存池.

可见CCAutoReleasePool需要和CCPoolManager结合来使用

与上面一样,直接发代码,源码里面都有清楚的注释,先看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); //删除栈顶元素中对应内存池中的对象pObject
void addObject(CCObject* pObject); //向栈顶元素中对应内存中添加对象pObject static CCPoolManager* sharedPoolManager(); //单例类,返回单例的实例
static void purgePoolManager(); //释放单例类 //将CCAutoreleasePool类声明为CCPoolManager的友元类,使得CCPoolManager成员函数中可以直接访问CCPoolManager中的私有变量
friend class CCAutoreleasePool;
};

CCPoolManager使用了一个数组来封装成一个栈.利用栈来管理内存池.

再看CCPoolManager类的实现文件,源码如下:

//--------------------------------------------------------------------
//
// CCPoolManager
//
//--------------------------------------------------------------------
static CCPoolManager* s_pPoolManager = NULL; //全局的静态变量 //单例类
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(); //新创建一个栈,其实就是用数组来模拟栈的行为,栈中的元素的类型为 CCAutoreleasePool*
m_pReleasePoolStack->init(); //初始化一个栈
m_pCurReleasePool = ; //将当前栈顶的元素置为NULL } CCPoolManager::~CCPoolManager()
{ finalize(); // we only release the last autorelease pool here
m_pCurReleasePool = ;
m_pReleasePoolStack->removeObjectAtIndex(); CC_SAFE_DELETE(m_pReleasePoolStack);
} //作清理栈内存的工作,栈中每个元素都是一个内存池,此函数将栈中每个内存池的内存都释放掉
void CCPoolManager::finalize()
{
if(m_pReleasePoolStack->count() > )
{
//CCAutoreleasePool* pReleasePool;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pReleasePoolStack, pObj)
{
if(!pObj)
break;
CCAutoreleasePool* pPool = (CCAutoreleasePool*)pObj;
pPool->clear();
}
}
} //压栈
void CCPoolManager::push()
{
CCAutoreleasePool* pPool = new CCAutoreleasePool(); //新建一个内存池,此时pPool 的引用计数为 ref = 1
m_pCurReleasePool = pPool; //并把新建的内存池赋值给栈顶,成了为栈顶元素 m_pReleasePoolStack->addObject(pPool); //把新建的内存池压入栈中,因为addObject内部作了retain的操作,此时pPool的引用计数为 ref = 2 pPool->release(); //引用计数再减1,是为了回到刚创建时的状态,此时ref = 1
} //弹栈,把当前的栈顶元素删除,把次栈顶元素变成栈顶元素
void CCPoolManager::pop()
{
//如果栈顶元素为NULL,则什么也不做,返回
if (! m_pCurReleasePool)
{
return;
} //得到栈中元素的个数
int nCount = m_pReleasePoolStack->count(); //把栈顶元素对应的内存池内存释放了
m_pCurReleasePool->clear(); //如果栈中元素的个数大于1,就是删除栈顶元素后,栈不为空
if(nCount > )
{
//把栈顶元素删除了
m_pReleasePoolStack->removeObjectAtIndex(nCount-); //把次栈顶元素赋值给当前的栈顶元素
m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - );
} } void CCPoolManager::removeObject(CCObject* pObject)
{
CCAssert(m_pCurReleasePool, "current auto release pool should not be null"); //删除栈顶元素中对应内存池中的对象pObject
m_pCurReleasePool->removeObject(pObject);
} void CCPoolManager::addObject(CCObject* pObject)
{
//把对象pObject添加到栈顶元素对应的内存池中
getCurReleasePool()->addObject(pObject);
} //得到栈顶元素对应的内存池
CCAutoreleasePool* CCPoolManager::getCurReleasePool()
{
//如果栈顶元素为NULL,也就是此栈中没有元素
if(!m_pCurReleasePool)
{
//则新建一个元素,并压入栈中,并把此元素赋值给当前栈顶元素
push();
} CCAssert(m_pCurReleasePool, "current auto release pool should not be null"); //返回栈顶元素
return m_pCurReleasePool; }

通过以上源码的分析可以看到:cocos2d-x是通过CCAutoreleasePool来保存所有需要自动释放内存的对象.而通过CCPoolManager来管理内存池的.

那么对象的释放到底是在什么时候释放的? 下篇文章介绍对象释放的时机


上一篇:嵌入式qt显示中文和隐藏鼠标


下一篇:sicily 1046. Plane Spotting(排序求topN)