cocos2d-x源码分析::内存管理机制

cocos2d-x的内存管理机制是回收池和引用计数合用来进行管理,这套机制一直为人们所津津乐道。
C++并没有内存管理的机制,都是用new/delete来进行对象的管理(STL和boost倒是有智能指针)

现在让我来介绍 一下cocos2d-x的内存管理机制。
cocos2d-x的内存管理机制用到的类有CCObject, CCAutoreleasePool, CCPoolManager这几个类

现在先讲CCObject,CCOjbect继承于CCCopying

//CCObject.h
class CC_DLL CCCopying
{
public:
    virtual CCObject* copyWithZone(CCZone* pZone);
};
//CCObject.cpp
CCObject* CCCopying::copyWithZone(CCZone *pZone)
{
    CC_UNUSED_PARAM(pZone);
    CCAssert(0, "not implement");
    return 0;
}

CCCopying其实是个接口,里面并没有任何实现。这里说一下宏命令CC_UNUESD_PARAM(),查看他的定义,很容易发现
#define CC_UNUSED_PARAM(unusedparam) (void)unusedparam
就是说这个宏完全没有执行任何命令,这样写的原因主要是历史遗留原因,ojb-c不存在纯虚函数并且传入参数不使用编译器会发出警告,这样用一个宏既可以防止警告也有一定的解释作用

CCCopying并没有父类,这样说来CCObject算是继承树上比较高的结点了,它负责了内存管理部分的引用计数
//CCObject.cpp
CCObject::CCObject(void)
:m_uAutoReleaseCount(0)
,m_uReference(1) // 构造时,引用数置为1
,m_nLuaID(0)
{
    static unsigned int uObjectCount = 0;

    m_uID = ++uObjectCount;
}

void CCObject::release(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");
    --m_uReference;

    if (m_uReference == 0)
    {
        delete this;
    }
}

void CCObject::retain(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");

    ++m_uReference;
}

可以看到,构造函数把引用数置为1,retain会把引用数加1,相反release会减1,每次release之后检测引用数,为0的话会析构当前对象。
另外cocos2d-x封装了一些容器,CCArray和CCDictionnary等,这些都是CCObject的容器,每当这些容器增加元素时,会调用一次retain,移除时会进行release

我们可以来对比一下下面的代码看一下引用计数和C++的new/delete的区别和优点

void function() {				
	int *arr[10];					
	int *num = new int(10);				
	arr[0] = num;					
	/*do something here*/                   	
	delete num; 					
	int test = arr[0];/*arr[0]已经丢失*/		
}

void function() {
	CCArray *arr = CCArray::createWithCapacity(10);
	CCObject *object = new CCObject; //引用 = 1
	arr->addOjbect(object); //引用 = 2
	/*do something here*/
	object->release(); //引用 = 1,未被析构
	CCObject *test = arr->getObjectAtIndex(0); //可以访问
	arr->removeObjectAtIndex(0); //引用 = 0,析构
}

通过对比很容易发现两者不一样,通过引用计数,release和delete不同,release并未等于析构,当所有对象都不持有该对象的指针时,才析构该对象,下面,我们再看看CCObject的另一个关于内存管理的函数,autorealease

//CCObject.cpp
CCObject* CCObject::autorelease(void)
{
    CCPoolManager::sharedPoolManager()->addObject(this);
    return this;
}

autorelease并未对引用进行任何的操作,只见他放进了CCPoolManager里面,这个其实就是内存池的管理者,那么我们先来看一下内存池是怎样的

//CCAutoreleasePool.h
class CC_DLL CCAutoreleasePool : public CCObject
{
    CCArray*    m_pManagedObjectArray;    
public:
    CCAutoreleasePool(void);
    ~CCAutoreleasePool(void);

    void addObject(CCObject *pObject);
    void removeObject(CCObject *pObject);

    void clear();
};

内存池其实就是一个CCArray的封装,代码很简单,这里就不贴源文件了,不过这里要注意几点
1.CCAutorelease是CCObject的子类,所以也是要进行引用计数等的管理的
2.尽管addObject和removeObject是向一个CCArray添加对象,可是内存池进行了一些操作,这两个操作并不会改变对象的引用数,也就是说,加入内存池并不改变对象的引用数

3.clear()就是内存池进行清理,会对内部所有的CCObject执行一次release()


那么CCObject的autorelease的auto体现在哪里呢,取决于CCAutoreleasePool调用clear的时机,我们可以看一看CCPoolManager

//CCAutoreleasePool.h
class CC_DLL CCPoolManager
{
    CCArray*    m_pReleasePoolStack;    
    CCAutoreleasePool*                    m_pCurReleasePool;

    CCAutoreleasePool* getCurReleasePool();
public:
    CCPoolManager();
    ~CCPoolManager();
    void finalize();
    void push();
    void pop();

    void removeObject(CCObject* pObject);
    void addObject(CCObject* pObject);

    static CCPoolManager* sharedPoolManager();
    static void purgePoolManager();

    friend class CCAutoreleasePool;
};

很高兴又见到了一个没有父类的家伙,从他的sharedPoolManager这个函数看来,他还是一个单件类,那就是名副其实的大哥类


内存管理在pop函数中体现

//CCAutoreleasePool.cpp
void CCPoolManager::pop()
{
    if (! m_pCurReleasePool)
    {
        return;
    }

    int nCount = m_pReleasePoolStack->count();
    m_pCurReleasePool->clear();
 
      if(nCount > 1)
      {
        m_pReleasePoolStack->removeObjectAtIndex(nCount-1);
        m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);
    }
}

CCPoolManager就是一个CCAutorelease的栈,每次pop都把栈顶的内存池进行处理,把栈顶内存池管理的元素release掉。至于pop在什么时候调用?看过我写的 主流程(mainloop)分析可以知道——
CCDiretor在mainloop()中调用了drawScene()和CCPoolManager::sharedPoolManager()->pop()
也就是说在每帧结束后,就会进行内存的管理


总结来说,cocos2d-x内存管理的引用计数部分通过retain/release来进行计数增减,而内存池管理就通过autorelease来进行管理,在每帧结束时自动回收


最后提一句,cocos2d-x的宏CREATE_FUNC(className)会自动生成一个静态的create函数,把该类生成,然后自动调用init()和autorelease()

包括cocos2d-x的一些类的create函数都是如此实现的,但autorelease会增加程序对内存管理的消耗,所以一般来说最好不要使用create进行生成
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: cocos2d-x是一款流行的开源游戏引擎,它可以用作开发本地移动游戏和桌面游戏。利用cocos2d-x游戏源码,开发人员可以快速构建流畅、高效、具有吸引力的游戏。该引擎使用C ++语言和脚本语言Lua来实现游戏开发,用户可以根据自己的需要进行选择。 cocos2d-x游戏源码包含许多强大的功能和工具,例如精灵、动画、场景管理、碰撞检测和音频控制等。通过这些功能,开发人员可以方便地创建各种类型的游戏,例如动作游戏、射击游戏、冒险游戏和益智游戏等。 此外,cocos2d-x游戏源码还具有高度定制化的特性,允许开发人员根据他们的需求自定义游戏元素。这种定制化可以通过改进游戏画面,添加新的模式和关卡,甚至整个新的游戏玩法来完成。 总之,cocos2d-x游戏源码是一款功能强大、易于使用和高度定制的游戏引擎,它可以帮助开发人员快速开发各种类型的游戏。无论你是专业开发人员还是无经验的游戏制作者,cocos2d-x都是一个极好的选择。 ### 回答2: Cocos2d-x游戏源码是使用Cocos2d-x引擎进行开发的游戏程序代码。Cocos2d-x引擎是一个开源的跨平台游戏引擎,可以支持iOS、Android、Windows Phone、Windows、MacOS和Linux等多个平台,并且提供了丰富的游戏开发API和工具集。Cocos2d-x游戏源码包含了游戏的核心逻辑、UI设计、动画效果、音频效果等各方面的代码,可以作为开发者学习和借鉴的重要资料。 由于Cocos2d-x引擎支持多种编程语言(如C++、Lua等),因此Cocos2d-x游戏源码也会有对应的编程语言版本。开发者可以通过阅读Cocos2d-x游戏源码,了解游戏开发过程中的技术细节,学习如何使用Cocos2d-x引擎进行游戏开发。同时,开发者也可以通过对Cocos2d-x游戏源码进行修改和优化,来满足游戏的特定需求,提升游戏的性能和用户体验。 总之,Cocos2d-x游戏源码是游戏开发者必备的重要资源,可以帮助开发者更好地了解游戏开发技术,提升游戏开发水平。 ### 回答3: cocos2d-x是一款优秀的游戏开发引擎,其源码包含了许多功能强大的游戏开发工具和API。使用cocos2d-x可以帮助开发者更快速更高效地开发出优秀的游戏作品。 cocos2d-x的游戏源码非常丰富,其包含了许多不同类型的游戏示例和模板,如平面射击、塔防、解谜等,这些示例可以帮助开发者更好地了解cocos2d-x的使用方法和原理。 cocos2d-x源码还包含了许多强大的API和工具,例如场景管理、动画控制、音频引擎等,这些工具和API能够帮助开发者更好地完成游戏的开发和调试。 此外,cocos2d-x源码还提供了完整的游戏开发框架,包括资源管理、内存管理、事件机制等,这些框架可以帮助开发者更好地组织代码和提高代码的可维护性。 总的来说,cocos2d-x游戏源码提供了丰富的工具和API,可以帮助开发者更高效地进行游戏开发,大大降低了开发难度和成本,是一款非常适合游戏开发者使用的引擎。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值