对cocos2d内存管理的一些理解

对cocos2dx内存管理机制的一些理解:

知识点1:主循环,启动游戏之后,在导演类的控制下,每帧执行一次循环。每一次循环所做的事情分为三段:1、判断是否需要释放CCDirector,如果需要则删除CCDirector所占用的资源。通常游戏结束时才执行这个步骤。2、调用drawscene绘制场景(分三部分解释绘制场景:首先掉用定时器触发事件然后判断是否切换场景,使用setNextStage切换最后调用visit绘制当前场景,当然实际过程要比这复杂的多,包括引擎脚本和OPenGL绘图)3、调用内存池管理类的pop函数弹出内存池,使得回收池中的所有对象释放一次。

知识点2:两种内存管理机制,1、引用计数,即创建对象之后计数1,之后被引用一次加1(retain),被释放一次减一(release),如果引用计数为零则在release中delete对象。2、自动内存池管理:在每一帧开始时创建一个内存池,把需要自动释放的对象指针加入内存池中,每一帧检测一次,当对象不再使用时则调用release释放掉。


执行释放内存操作的只有release中的delete方法。其他的都是对引用计数的加减。


从autorelease开始追踪执行:

CCObject* CCObject::autorelease(void)

{   CCPoolManager::sharedPoolManager()->addObject(this);//CCPoolManager是一个单例类,类似于CCDirector

    return this;

}

转到addObject(this)

void CCPoolManager::addObject(CCObject* pObject)

{     getCurReleasePool()->addObject(pObject);//含有两布操作,getCurReleasePool(),然后addObject(pObject)

}

先看getCurReleasePool

CCAutoreleasePool* CCPoolManager::getCurReleasePool()

{     if(!m_pCurReleasePool)   //指向当前的自动释放池,若为NULL,则执行push,在内存池栈(动态数组)中压入一个内存池

  {         push();  

   }  

   CCAssert(m_pCurReleasePool, "current auto release pool should not be null");   

  return m_pCurReleasePool;

}

附push代码

void CCPoolManager::push()

{     CCAutoreleasePool* pPool = new CCAutoreleasePool();       //ref = 1    ,创建内存池,引用计数为1

 m_pCurReleasePool = pPool;  

   m_pReleasePoolStack->addObject(pPool);                   //ref = 2  ,addObject操作pPool引用计数+1 =2

  pPool->release();                                       //ref = 1   pPool引用计数减1

}

再看addObject

void CCAutoreleasePool::addObject(CCObject* pObject)

{     m_pManagedObjectArray->addObject(pObject);    //内存池的数组容器中添加对象,引用计数加1

 CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1");   

  ++(pObject->m_uAutoReleaseCount);   //自动释放次数,下面介绍不为1的情形

  pObject->release(); // no ref count, in this case autorelease pool added. } //引用计数减1

最后再看一下主循环的最后一个步骤:弹出内存池

void CCPoolManager::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);//当前自动释放池指针指向第二个(可为空)。  

 }    

 }

clear函数代码如下:

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);       //每个对象的自动释放次数减1    

#ifdef _DEBUG          

   nIndex--;

#endif         

}       

  m_pManagedObjectArray->removeAllObjects();  //下面转入

   }

}

转入removeAllObject

void ccArrayRemoveAllObjects(ccArray *arr)

{     while( arr->num > 0 )  

   {        

 (arr->arr[--arr->num])->release();   

  }

}

自动回收池容器中的对象各释放一次。若对象中间没有被使用则会被释放掉,由于当前帧结束时才会释放,所以这期间有足够的时间为他添加引用。另外,再CCObject类的析构函数中也会释放一次,可以在中间调用,也会在对象离开作用域的时候释放,避免了内存泄露。

对象的指针传递(自动释放计数不为1

CCTableViewCell *CCTableView::dequeueCell()

{     CCTableViewCell *cell;    

 if (m_pCellsFreed->count() == 0)

 {         cell = NULL;    

 } 

else 

{         cell = (CCTableViewCell*)m_pCellsFreed->objectAtIndex(0);  //对象的指针传递

       cell->retain();        //引用计数加1

 m_pCellsFreed->removeObjectAtIndex(0);   //引用计数减1

      cell->autorelease(); //当前对象的自动释放计数再加1

    }   

  return cell;

}

自动释放计数的唯一使用地方:

void CCAutoreleasePool::removeObject(CCObject* pObject) {     for (unsigned int i = 0; i < pObject->m_uAutoReleaseCount; ++i) //多次自动释放计数时(看下一行注释) //1

    {         m_pManagedObjectArray->removeObject(pObject, false);  //首先从自动释放池中删除所有指针(同上) //2

   }

}

//转到CCArray的removeObject

void CCArray::removeObject(CCObject* object, bool bReleaseObj/* = true*/)

{     ccArrayRemoveObject(data, object, bReleaseObj);   //3

}


void ccArrayRemoveObjectAtIndex(ccArray *arr, unsigned int index, bool bReleaseObj/* = true*/) //4

{     CCAssert(arr && arr->num > 0 && index < arr->num, "Invalid index. Out of bounds");  

   if (bReleaseObj)  

   {         CC_SAFE_RELEASE(arr->arr[index]);  //安全释放,可能是对同一对象的多次释放.当已经释放后,第三行的remove返回空,不再向下执行.

   }        

  arr->num--;         

 unsigned int remaining = arr->num - index;  

   if(remaining>0)   

  {         memmove((void *)&arr->arr[index], (void *)&arr->arr[index+1], remaining * sizeof(CCObject*));   

  }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值