您的位置:首页 > 移动开发 > Cocos引擎

cocos2d-x 内存管理机制

2015-05-05 16:56 337 查看
转自:http://www.2cto.com/kf/201403/284698.html

参考:http://blog.leafsoar.com/archives/2013/05-29.html

http://blog.leafsoar.com/archives/2013/05-22.html
http://blog.leafsoar.com/archives/2013/06-04.html


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


new和release一般成对存在,所以,new和release是好基友!而手动内存管理一般不再使用retain。

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,那么显然其内存管理形式也采用引用计数的。

这时看到类中的 m_pManagedObjectArray 数组,我们将对象autorelease后,都是将对象添加到这个数组中的,所以说是对象自动管理(释放)池。

再来回顾一下前面这个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.
}


首先是将对象添加到数组中,然后将对象自动管理变量++,那么对象的 m_uAutoReleaseCount =1,也就是表明其为自动管理对象。

然后对对象进行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++;
}


看到object->retain()方法了吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: