1. reference counting mechanism
To understand the reference counting mechanism of cocos2dx, Let's first look at the CCObject class.
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;};
Note:
● When m_uReference is set to 0, the object will be automatically released. When the object is referenced once, m_uReference will + 1. When the object is created, it will be initialized to 1.
● When m_uAutoReleaseCount! = 0 indicates that the object is automatically released (autorelease ).
● Void retain (void) can operate m_uReference + 1 to prevent objects from being released.
● RetainCount () returns the m_uReference Value
● Tracking the void release () method, we will find that it is to perform the-1 operation on the reference count m_uReference. If it is 0, the object will be deleted.
void CCObject::release(void){ CCAssert(m_uReference > 0, "reference count should greater than 0"); --m_uReference; if (m_uReference == 0) { delete this; }}
2. Manual memory management with reference count
Therefore, if we want to manually manage the memory release, we can use this method,
CCSprite * sprite1 = new CCSprite (); sprite1-> initWithFile ("CloseNormal.png"); CCLOG ("sprite1 retain: % d", sprite1-> retainCount ()); // sprite1 retain: 1this-> addChild () operate CCLOG ("sprite1 retain: % d", sprite1-> retainCount (); // sprite1 retain: 2sprite1-> release (); CCLOG ("sprite1 retain: % d ", sprite1-> retainCount (); // sprite1 retain: 1this-> removeChild (sprite1); // perform-1 on m_uReference, after tracking, we will find that the CC_SAFE_RELEASE () secure release operation CCLOG ("sprite1 retain: % d", sprite1-> retainCount (); // sprite1 retain:-17891602
New and release exist in pairs. Therefore, new and release are good friends! Manual memory management generally does not use retain.
3. Automatic autorelease Management
Do you still remember how to create a Sprite in helloWorld?
CCSprite* pSprite = CCSprite::create("HelloWorld.png");
Tracking 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;}
We can know above: create = new + autorelease
So what is autorelease? Let's track the autorelease method:
CCObject* CCObject::autorelease(void){ CCPoolManager::sharedPoolManager()->addObject(this); return this;}
Enter the addObject Method
void CCPoolManager::addObject(CCObject* pObject){ getCurReleasePool()->addObject(pObject);}
Enter the addObject Method
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.}
Then we can find two classes:
CCPoolManager Automatic Object Management class. As the name suggests, this class is known as the class for managing the Automatic Object release pool. It is a singleton class, which is used to return the CCAutoreleasePool
CCAutoreleasePool object Automatic Management (release) pool.
From the above, we can see that the object is added to the m_pManagedObjectArray array.
m_pManagedObjectArray->addObject(pObject);
Let's take a look at the CCAutoreleasePool class.
class CC_DLL CCAutoreleasePool : public CCObject{ CCArray* m_pManagedObjectArray; public: CCAutoreleasePool(void); ~CCAutoreleasePool(void); void addObject(CCObject *pObject); void removeObject(CCObject *pObject); void clear();};
It is worth noting that this class also inherits from CCObject, so obviously its memory management form also uses reference counting.
In this case, we can see the m_pManagedObjectArray array in the class. After the object autorelease is added to this array, the object is automatically managed (released.
Let's review the previous addObject method.
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.}
First, add the object to the array and then automatically manage the variable ++ of the object. Then, the m_uAutoReleaseCount of the object is 1, indicating that it is an automatically managed object.
Then perform the release operation on the object, that is, to reduce the reference count of the object by 1. As to why the object should be released, the following explanation is provided:
① When a CCSprite object is created and new is used, the reference count m_uReference is 1. This should not be hard to understand: CCSprite is inherited from CCObject, but it is known in the previous CCObject constructor that after new creates an instance object, its reference count m_uReference = 1, whether to automatically manage the variable m_uAutoReleaseCount = 0 (indicating that the object is not added to the automatic management (release) pool for automatic management ).
② Then the object autorelease is used to add the object to the Auto Release pool, and the following:
M_pManagedObjectArray-> addObject (pObject); When a managed object is added to the automatic management pool (adding the object to the array), the object will be retained, therefore, m_uReference is changed to m_uReference = 2.
③ The final release is used to convert the reference count to 1 again. In this way, from object creation to object automatic management pool, the reference count is still 1, and the managed value is also 1 (the characterization object is automatically managed ).
If you don't believe it, let's track m_pManagedObjectArray-> addObject (pObject)
void CCArray::addObject(CCObject* object){ ccArrayAppendObjectWithResize(data, object);}
Enter
/** Appends an object. Capacity of arr is increased if needed. */void ccArrayAppendObjectWithResize(ccArray *arr, CCObject* object){ccArrayEnsureExtraCapacity(arr, 1);ccArrayAppendObject(arr, object);}
Before entering
/** 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++;}
You can see the object-> retain () method.