• Cocos2d-x学习笔记(十四)CCAutoreleasePool具体解释


    原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38964637


    前言

    之前学了那么多的内容。差点儿全部的控件都要涉及内存管理类CCAutoreleasePool。所以这一次的学习笔记,我们一起来看看CCAutoreleasePool,先从CCObject的autorelease方法入手。


    CCObject::autorelease

    CCObject* CCObject::autorelease(void)
    {
        // 将当前对象加入到内存池中
        CCPoolManager::sharedPoolManager()->addObject(this);
                                                
        // 将当前对象设置为已被内存池管理
        m_bManaged = true;
        return this;
    }
    autoRelease类并不复杂。由代码中的凝视能够看出主要还是CCPoolManager的操作,而这部分内容被写在了CCAutoreleasePool中,让我们一起看看吧。


    CCAutoreleasePool.h

    class CC_DLL CCAutoreleasePool : public CCObject
    {
        // 保存全部加入到释放池中的对象。注意CCArray内部是通过将对象retain 然后存储起来的,应用计数会添加1
        CCArray* m_pManagedObjectArray;    
    public:
        CCAutoreleasePool(void);
        ~CCAutoreleasePool(void);
                                       
        // 将对象加入到自己主动释放池
        void addObject(CCObject *pObject);
                                       
        // 将对象从自己主动释放池中移除
        void removeObject(CCObject *pObject);
                                       
        // 将自己主动释放池中的对象释放掉
        void clear();
    };
                                       
    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;
    };

    CCAutoreleasePool.cpp

    // 静态成员变量。存储整个程序中使用的CCPoolManager对象
    static CCPoolManager* s_pPoolManager = NULL;
                        
    CCAutoreleasePool::CCAutoreleasePool(void)
    {
        //初始化队列,用以保存加入到池中的对象
        m_pManagedObjectArray = new CCArray();
        m_pManagedObjectArray->init();
    }
                        
    CCAutoreleasePool::~CCAutoreleasePool(void)
    {
        CC_SAFE_DELETE(m_pManagedObjectArray);
    }
                        
    // 将对象加入到自己主动释放池中
    void CCAutoreleasePool::addObject(CCObject* pObject)
    {
        // 将对象retain 保存到队列中
        m_pManagedObjectArray->addObject(pObject);
                        
        // 确保此时对象的应用计数最少是2
        CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1");
                        
        // 调用对象的release方法,将引用计数减1
        pObject->relearese();
    }
                        
    void CCAutoreleasePool::removeObject(CCObject* pObject)
    {
        // 从自己主动释放池中移除对象,使该对象不被自己主动释放池管理,当然也不会自己主动释放,第二个參数为false,,由于addObject被没有使引用计数添加,全部这里也不能使应用计数有变化
        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_bManaged = false;
                //(*it)->release();
                //delete (*it);
    #ifdef _DEBUG
                nIndex--;
    #endif
            }
            // 移除全部的在队列中的对象。依次调用全部对象的release方法
            m_pManagedObjectArray->removeAllObjects();
        }
    }
                        
                        
    //--------------------------------------------------------------------
    //
    // 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()
    {
        // 向自己主动释放池队列中加入一个新的自己主动释放池。将新加入的自己主动释放池作为当前的
        // 自己主动释放池使用
        CCAutoreleasePool* pPool = new CCAutoreleasePool();       //ref = 1
        m_pCurReleasePool = pPool;
                        
        m_pReleasePoolStack->addObject(pPool);                   //ref = 2
                        
        pPool->release();                                       //ref = 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);
        }
    }
                        
    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()
    {
                        
        // 获取当前的自己主动释放池
        // 假设当前的自己主动释放池为空。说明自己主动释放池队列中也为空
        // 通过push方法。加入新的自己主动释放池
        if(!m_pCurReleasePool)
        {
            push();
        }
                        
        CCAssert(m_pCurReleasePool, "current auto release pool should not be null");
                        
        return m_pCurReleasePool;
    }
    自己主动释放池管理者通过pop方法,将当前自己主动释放池中的全部对象调用release方法进行释放,pop方法是什么时候在什么地方进行调用的呢?事实上答案就在我们之前看到过的mainloop方法中:

    void CCDisplayLinkDirector::mainLoop(void)
    {
        if (m_bPurgeDirecotorInNextLoop)
        {
            m_bPurgeDirecotorInNextLoop = false;
            purgeDirector();
        }
        else if (! m_bInvalid)
         {
             // 绘制场景
             drawScene();
                           
             // 释放自己主动释放池
             CCPoolManager::sharedPoolManager()->pop();        
         }
    }
    在每一帧绘制完毕之后,当前的自己主动释放池将会被清理,全部调用了autorelease操作的对象都会被调用release方法。降低其引用计数。假设我们创建的对象调用了autorelease,那么在稍后帧绘制之后。自己主动释放池被清理的时候此对象的引用计数将被减1,此对象假设没有在其它地方被retain。那么它将会被释放掉。
    在对象的使用上,为保证对象能被正确的释放,须要时刻知道此对象的引用计数为多少,可是非常多时候能做到这点非常难。除非对全部的接口都非常了解,知道当中是否对当前对象做了retain操作或者release操作。假设做不到这点,能够依照cocos2d-x框架中这种原则去做
    1、作为參数传进来的对象。假设你要长期的使用或者管理它,请 retain,不用的时候记得release
    2、作为參数传进来的对象,他不是你创建或者retain的,假设你不确定他从哪里来,外面是否知道你会release掉他。请别随便调用release
    3、假设你撇开自己主动释放池,new了一个对象而不调用autorelease,在不使用的时候直接将对象delete掉。这种做法是非常不安全的。除非你创建的对象真的仅仅有你在使用而没有被其它对象retain。但并不是代表你不能自己new和delete管理对象,因时而异。
    4、创建一个新的对象。调用了对象的autorelease方法,假设想长期的使用他,请使用retain方法(包含addChild到自身,addObject到某个CCArray中),清除时使用release方法(removeChild、CCArray的removeObject等)


    參考资料

    1)cocos2d-x学习笔记内存管理之autorelease http://hi.baidu.com/357802636/item/7bb3e71a7838efd6be904200

  • 相关阅读:
    RESTful Web 服务
    关于 Java API for RESTful Web Services (JAX-RS) 介绍
    IPV6正则表达式
    使用MyBatis-generator 自动生成MyBatis代码
    JSON.stringfy妙用
    浅拷贝与深拷贝
    vue双向绑定原理与实践
    vue路由当中的导航钩子中关于next()方法的理解
    Promise 异步备忘
    封装van-popup为自己的弹窗组件解决v-moel props单向数据流不能修改的问题。
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/6944624.html
Copyright © 2020-2023  润新知