1.引用计数机制
要了解cocos2dx引用计数的机制,首先我们来看看CCObject这个类
class CC_DLL CCObject : public CCCopying { public: // object id, CCScriptSupport need public m_uID unsigned int m_uID; // Lua reference id int m_nLuaID; protected: // count of references unsigned int m_uReference; // count of autorelease unsigned int m_uAutoReleaseCount; public: CCObject(void); /** * @lua NA */ virtual ~CCObject(void); void release(void); void retain(void); CCObject* autorelease(void); CCObject* copy(void); bool isSingleReference(void) const; unsigned int retainCount(void) const; virtual bool isEqual(const CCObject* pObject); virtual void acceptVisitor(CCDataVisitor &visitor); virtual void update(float dt) {CC_UNUSED_PARAM(dt);}; friend class CCAutoreleasePool; };
● 当m_uReference=0时会自动释放该对象,每引用一次对象的时候,m_uReference会+1,当object被创建,会初始化为1.
● 当m_uAutoReleaseCount !=0时表示该对象自动释放(autorelease)。
●void retain(void) 对m_uReference+1操作,可以防止对象被释放
●retainCount() 返回m_uReference值
● 跟踪一下void release()方法,我们会发现是对引用计数m_uReference进行-1操作,为0时删除对象
void CCObject::release(void) { CCAssert(m_uReference > 0, "reference count should greater than 0"); --m_uReference; if (m_uReference == 0) { delete this; } }
2.使用引用计数手动管理内存
因此,如果我们想手动来管理内存的释放,我们可以使用这样子,
CCSprite* sprite1=new CCSprite(); sprite1->initWithFile("CloseNormal.png"); CCLOG("sprite1 retain:%d",sprite1->retainCount());//sprite1 retain:1 this->addChild(sprite1); //addChild会对引用计数+1,可以跟踪看一下,最后会对object->retain()操作 CCLOG("sprite1 retain:%d",sprite1->retainCount());//sprite1 retain:2 sprite1->release(); CCLOG("sprite1 retain:%d",sprite1->retainCount());//sprite1 retain:1 this->removeChild(sprite1); //对m_uReference进行-1,跟踪一下会发现对object进行CC_SAFE_RELEASE()安全释放操作 CCLOG("sprite1 retain:%d",sprite1->retainCount());//sprite1 retain:-17891602
3.自动管理autorelease
还记得helloWorld里面怎么创建一个Sprite吗?
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
跟踪CCSprite::create()
CCSprite* CCSprite::create(const char *pszFileName) { CCSprite *pobSprite = new CCSprite(); if (pobSprite && pobSprite->initWithFile(pszFileName)) { pobSprite->autorelease(); return pobSprite; } CC_SAFE_DELETE(pobSprite); return NULL; }
上上面我们可以知道 : create=new+autorelease
那么autorelease是什么呢,我们接着跟踪进入autorelease方法:
CCObject* CCObject::autorelease(void) { CCPoolManager::sharedPoolManager()->addObject(this); return this; }进入其中的addObject方法
void CCPoolManager::addObject(CCObject* pObject) { getCurReleasePool()->addObject(pObject); }再进入 addObject方法
void CCAutoreleasePool::addObject(CCObject* pObject) { m_pManagedObjectArray->addObject(pObject); CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1"); ++(pObject->m_uAutoReleaseCount); pObject->release(); // no ref count, in this case autorelease pool added. }然后我们可以发现俩个类:
CCPoolManager 对象自动管理类,这个类顾名思义就知道是对对象自动释放池进行管理的类,它是一个单例类,这里用来返回CCAutoreleasePool
CCAutoreleasePool 对象自动管理(释放)池。
从上面我们可以看到这样一句,将object添加到m_pManagedObjectArray 数组
m_pManagedObjectArray->addObject(pObject);
我们来看一下CCAutoreleasePool 这个类
class CC_DLL CCAutoreleasePool : public CCObject { CCArray* m_pManagedObjectArray; public: CCAutoreleasePool(void); ~CCAutoreleasePool(void); void addObject(CCObject *pObject); void removeObject(CCObject *pObject); void clear(); };
值得注意的是,这个类也是继承自CCObject,那么显然其内存管理形式也采用引用计数的。
再来回顾一下前面这个addObject方法
void CCAutoreleasePool::addObject(CCObject* pObject) { m_pManagedObjectArray->addObject(pObject); CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1"); ++(pObject->m_uAutoReleaseCount); pObject->release(); // no ref count, in this case autorelease pool added. }
然后对对象进行release,也即对对象的引用计数进行减1的操作,至于为什么要释放,这里解释下:
①首先一个CCSprite对象被创建,使用的是new,那么其引用计数 m_uReference=1。这个应该不难理解吧:CCSprite是继承自CCObject,而在前面CCObject的构造方法中就知道,new创建一个实例对象后,其引用计数m_uReference=1,而是否自动管理变量 m_uAutoReleaseCount=0(表示对象未添加到自动管理(释放)池中自动管理)。
②接着对象autorelease,那么就是将对象添加到自动释放池中,而其中的:
m_pManagedObjectArray->addObject(pObject); 将被管理对象添加到自动管理池中的过程中(将对象添加到数组中),其会对对象进行retain操作的,所以 m_uReference 就变成了 m_uReference=2。
③所以最后的release是为了将引用计数重新变成为1。这样的话,从对象创建,到被放到对象自动管理池,引用计数依然为1,被管理值也为1(表征对象是自动管理)。
不信的话,下面我们来跟踪一下m_pManagedObjectArray->addObject(pObject)
void CCArray::addObject(CCObject* object) { ccArrayAppendObjectWithResize(data, object); }进入
/** Appends an object. Capacity of arr is increased if needed. */ void ccArrayAppendObjectWithResize(ccArray *arr, CCObject* object) { ccArrayEnsureExtraCapacity(arr, 1); ccArrayAppendObject(arr, object); }
/** Appends an object. Behavior undefined if array doesn't have enough capacity. */ void ccArrayAppendObject(ccArray *arr, CCObject* object) { CCAssert(object != NULL, "Invalid parameter!"); object->retain(); arr->arr[arr->num] = object; arr->num++; }