上一篇文件讲到了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 > 1, "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 = 0; i < pObject->m_uAutoReleaseCount; ++i) { //将对象pObject从内存池中删除掉 m_pManagedObjectArray->removeObject(pObject, false); } } //清理内存池 void CCAutoreleasePool::clear() { //如果内存池中的元素个数大于0 if(m_pManagedObjectArray->count() > 0) { //CCAutoreleasePool* pReleasePool; #ifdef _DEBUG int nIndex = m_pManagedObjectArray->count() - 1; //内存池中,也就是数组的最后一个元素的索引 #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 = 0; //将当前栈顶的元素置为NULL } 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() { 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 > 1) { //把栈顶元素删除了 m_pReleasePoolStack->removeObjectAtIndex(nCount-1); //把次栈顶元素赋值给当前的栈顶元素 m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2); } } 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来管理内存池的.
那么对象的释放到底是在什么时候释放的? 下篇文章介绍对象释放的时机