我只是一个在沙滩上捡贝壳的小男孩,梦想有一天可以发现知识的真理~~~

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.
    }
posted @ 2017-05-08 18:28  瓜不甜  阅读(102)  评论(0)    收藏  举报

全栈开发工程师 - 一只菜鸟的成长之路

这是一位软件开发工程师的个人站,内容主要是网站开发方面的技术文章,大部分来自学习或工作,部分来源于网络,希望对大家有所帮助。

联系我:2351180282@qq.com