cocos2dx 内存管理(3)---CCPoolManager浅析

前两篇博文我们我们详细分析了cocos2dx的内存管理机制的实现,现在我们在这里简单总结一下:


对于一个对象来说,一般流程:

  1. Object obj=new  Object() ,自引用计数为1
  2. 然后调用obj.autorelease()方法,进行自动释放,将obj添加到自动释放池,并保持自引用计数为1
  3. 在这里可以对obj引用,比如将obj添加到一个Layer中,则Layer此时是obj的使用者
  4.  然后程序会在主循环去判断,绘制第一帧的时候,解除自动释放池对obj的引用(release操作),将obj交给使用者管理
  5. 所谓交给使用者管理,便是链式反应,即释放一个对象,那么他所引用的对象也会被释放

之前我们分析的时候,知道自动释放池是交给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;
};


当我们调用push()方法时, CCPoolManager会把CCAutoreleasePool放进m_pReleasePoolStack这个数组里面,要用的时候再用getCurReleasePool()取出来。



这里我们关注一下addObject方法

void CCPoolManager::addObject(CCObject* pObject)
{
    getCurReleasePool()->addObject(pObject);
}

getCurReleasePool():

CCAutoreleasePool* CCPoolManager::getCurReleasePool()
{
    if(!m_pCurReleasePool)
    {
        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
    m_pCurReleasePool = pPool;

    m_pReleasePoolStack->addObject(pPool);                   //ref = 2

    pPool->release();                                       //ref = 1
}


我们发现,,当我们将对象添加到自动释放池的时候,也就是调用addObject方法,会首先判断是否有当前的释放池,如果没有则创建,如果有,则直接使用,可想而知,在任何使用,任何情况,通过 addObject 只需要创建一个释放池便已经足够使用了。事实上也是如此。


然后再看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;*/
}

还记得主循环对自动释放池的pop操作吗,如上,先对自动释放池clear之后,从自动释放池数组中删除该对象自动管理池;然后将数组中的倒数第二个自动释放池作为当前自动释放池。 看到这里  我就不解了!什么情况下才能用到多个释放池?按照设计的逻辑根本用不到。带着这个疑问,在push添加一句注释看看

运行程序,发现实际的使用中,push 只被调用了两次!我们知道,通过 addObject 可能会自动调用 push() 一次,但也仅有一次,所以一定是哪里手动调用了 push() 方法,才会出现这种情况,通过查看引擎源码,发现在bool CCDirector::init(void)中,

有这么一句:

bool CCDirector::init(void)
{
  CCLOG("cocos2d: %s", cocos2dVersion());

  ...
  ...
  m_dOldAnimationInterval = m_dAnimationInterval = 1.0 / kDefaultFPS;
    m_pobScenesStack = new CCArray();
    m_pobScenesStack->init();

  ...
  ...
    m_fContentScaleFactor = 1.0f;

  ...
  ...
    // touchDispatcher
    m_pTouchDispatcher = new CCTouchDispatcher();
    m_pTouchDispatcher->init();

    // KeypadDispatcher
    m_pKeypadDispatcher = new CCKeypadDispatcher();

    // Accelerometer
    m_pAccelerometer = new CCAccelerometer();


    // 这里手动调用了 push 方法,而在这之前的初始化过程中,间接的使用了 CCObject 的 autorelease,已经触发过一次 push 方法
    CCPoolManager::sharedPoolManager()->push();

    return true;
}

所以我们便能够看到 push 方法被调用了两次 ,但其实如果我们把这里的手动调用放在方法的开始处,或者干脆就不使用  CCPoolManager::sharedPoolManager()->push();  ,对程序也没任何影响,这样从头到尾, 只创建了一个自动释放池,而这里多创建的一个并没有多大的用处。  或者用处不甚明显,因为多创建一个释放池是有其效果的,效果具体体现在哪里,那就是  可以使调用 push() 方法之前的对象,多存活一帧。 ,因为 pop 方法只对当前释放池做了 clear 释放。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值