coco2d-x的内存管理机制
cocos2d学习笔记
cocos2d-x学习总结
学习之道,在于精益求精。
内存管理
1 class CC_DLL CCObject : public CCCopying
2 {
3 public:
4 … …
5 protected:
6 // count of references
7 unsigned int m_uReference;
8 // count of autorelease
9 unsigned int m_uAutoReleaseCount;
10 public:
11 void release(void);
12 void retain(void);
13 CCObject* autorelease(void);
14 … ….
15 }
16
17 CCObject::CCObject(void)
18 : m_nLuaID(0)
19 , m_uReference(1) // when the object is created, the reference count of it is 1
20 , m_uAutoReleaseCount(0)
21 {
22 … …
23 }
24
25 void CCObject::release(void)
26 {
27 CCAssert(m_uReference > 0, "reference count should greater than 0");
28 –m_uReference;
29
30 if (m_uReference == 0)
31 {
32 delete this;
33 }
34 }
35
36 void CCObject::retain(void)
37 {
38 CCAssert(m_uReference > 0, "reference count should greater than 0");
39
40 ++m_uReference;
41 }
42
43 CCObject* CCObject::autorelease(void)
44 {
45 CCPoolManager::sharedPoolManager()->addObject(this);
46 return this;
47 }
引用计数管理
CCObject 内部维护着一个引用计数,引用计数为 0 就自动释放 ~(如果么有直接做如 delete 之类的操作) 函数:如下
//CCCopying: 是一个克隆函数的抽象类,而且竟然是public的
class CC_DLL CCObject : public CCCopying
{
protected:
//.....
unsigned int m_uReference; // 引用计数
//.....
public:
void release(void);// 释放
//.....
}
//实现:
void CCObject::release(void)
{
CCAssert(m_uReference > 0, "....");//断言
--m_uReference;
if (m_uReference == 0)
{
delete this;
}
}
void CCObject::retain(void)
{
CCAssert(m_uReference > 0, "....");//断言
++m_uReference;
}
一个简单的自动管理原则:CCObject 内部维护着一个引用计数,引用计数为 0 就自动释放 ~(如果么有直接做如 delete 之类的操作)。那么此时可以预见,管理内存的实质就是管理这些 “引用计数” 了!使用 retain 和 release 方法对引用计数进行操作!
这是一个十分智能的释放,它不是简单的delete,而是看是否已经没有指针指向他了,它再释放。
但并没有自动释放的功能,一切都要手动来实现
你必须自动释放它,但不会出现原始的delete null的现象
子类的使用情况
CCLayer *CCLayer::create()
{
CCLayer *pRet = new CCLayer();
if (pRet && pRet->init())
{
pRet->autorelease();
return pRet;
}
else
{
CC_SAFE_DELETE(pRet);
return NULL;
}
}
我还没有找到一个用来增加计数的,
内存池管理
为什么要有自动释放池 及其作用
我们知道 cocos2d-x 使用了自动释放池,自动管理对象,知其然!其所以然呢?为什么需要自动释放池,它在整个框架之中又起着什么样的作用!在了解这一点之前,我们需要 知道 CCObject 从创建之初,到最终销毁,经历了哪些过程。在此,一叶总结以下几点:
刚创建的对象,而 为了保证在使用之前不会释放(至少让它存活一帧),所以自引用(也就是初始为1) 为了确定是否 实际使用,所以需要在一个合适的时机,解除自身引用。 而这个何时的时机正是在帧过度之时。 帧过度之后的对象,用则用矣,不用则弃! 由于已经解除了自身引用,所以它的引用被使用者管理(一般而言,内部组成树形结构的链式反应,如 CCNode)。 链式反应,也就是,如果释放一个对象,也会释放它所引用的对象。 上面是一个对象的大致流程,我们将对象分为两个时期,一个是刚创建时期,自引用为 1(如果为 0 就会释放对象,这是基本原则,所以要大于 0) 的时期,另一个是使用时期。上面说到,为了保证创建时期的对象不被销毁,所以自引用(并没有实际的使用)初始化为 1,这就意味着我们需要一个合适的时机,来解除这样的自引用。
何时?在帧过度之时!(这样可保证当前帧能正确使用对象而没有被销毁。)怎么样释放?由于是自引用,我们并不能通过其它方式访问到它,所以就有了自动释放池,我们 变相的将“自引用”转化“自动释放池引用”,来标记一个 “创建时期的对象”。然后在帧过度之时,通过自动释放池管理,统一释放 “释放池引用”,也就意味着,去除了“自身引用”。帧过度之后的对象,才是真正的被使用者所管理。 下面我们用代码来解释上述过程。
通常我们使用 create(); 方法来创建一个自动管理的对象,而其内部实际操作如下:
// 初始化一个对象
static CCObject* create()
{
// new CCObject 对象
CCObject *pRet = new CCObject();
if (pRet && pRet->init())
{
// 添加到自动释放池
pRet->autorelease();
return pRet;
}
else
{
delete pRet;
pRet = 0;
return 0;
}
}
// 我们看到初始化的对象 自引用 m_uReference = 1
CCObject::CCObject(void)
:m_uAutoReleaseCount(0)
,m_uReference(1) // when the object is created, the reference count of it is 1
,m_nLuaID(0)
{
static unsigned int uObjectCount = 0;
m_uID = ++uObjectCount;
}
// 标记为自动释放对象
CCObject* CCObject::autorelease(void)
{
// 添加到自动释放池
CCPoolManager::sharedPoolManager()->addObject(this);
return this;
}
// 继续跟踪
void CCPoolManager::addObject(CCObject* pObject)
{
getCurReleasePool()->addObject(pObject);
}
// 添加到自动释放池的实际操作
void CCAutoreleasePool::addObject(CCObject* pObject)
{
// 内部是由一个 CCArray 维护自动释放对象,并且此操作 会使引用 + 1
m_pManagedObjectArray->addObject(pObject);
// 由于初始化 引用为 1,上面又有操作,所以引用至少为 2 (可能还被其它所引用)
CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1");
++(pObject->m_uAutoReleaseCount);
// 变相的将自身引用转化为释放池引用,所以减 1
pObject->release(); // no ref count, in this case autorelease pool added.
}

浙公网安备 33010602011771号