cocos2d-x源码分析::内存管理机制
来源:互联网 发布:软件制作 编辑:程序博客网 时间:2024/06/05 20:40
cocos2d-x的内存管理机制是回收池和引用计数合用来进行管理,这套机制一直为人们所津津乐道。
C++并没有内存管理的机制,都是用new/delete来进行对象的管理(STL和boost倒是有智能指针)
现在让我来介绍 一下cocos2d-x的内存管理机制。
cocos2d-x的内存管理机制用到的类有CCObject, CCAutoreleasePool, CCPoolManager这几个类
CCCopying其实是个接口,里面并没有任何实现。这里说一下宏命令CC_UNUESD_PARAM(),查看他的定义,很容易发现
#define CC_UNUSED_PARAM(unusedparam) (void)unusedparam
就是说这个宏完全没有执行任何命令,这样写的原因主要是历史遗留原因,ojb-c不存在纯虚函数并且传入参数不使用编译器会发出警告,这样用一个宏既可以防止警告也有一定的解释作用
CCCopying并没有父类,这样说来CCObject算是继承树上比较高的结点了,它负责了内存管理部分的引用计数
可以看到,构造函数把引用数置为1,retain会把引用数加1,相反release会减1,每次release之后检测引用数,为0的话会析构当前对象。
另外cocos2d-x封装了一些容器,CCArray和CCDictionnary等,这些都是CCObject的容器,每当这些容器增加元素时,会调用一次retain,移除时会进行release
我们可以来对比一下下面的代码看一下引用计数和C++的new/delete的区别和优点
通过对比很容易发现两者不一样,通过引用计数,release和delete不同,release并未等于析构,当所有对象都不持有该对象的指针时,才析构该对象,下面,我们再看看CCObject的另一个关于内存管理的函数,autorealease
autorelease并未对引用进行任何的操作,只见他放进了CCPoolManager里面,这个其实就是内存池的管理者,那么我们先来看一下内存池是怎样的
内存池其实就是一个CCArray的封装,代码很简单,这里就不贴源文件了,不过这里要注意几点
1.CCAutorelease是CCObject的子类,所以也是要进行引用计数等的管理的
2.尽管addObject和removeObject是向一个CCArray添加对象,可是内存池进行了一些操作,这两个操作并不会改变对象的引用数,也就是说,加入内存池并不改变对象的引用数
CCPoolManager就是一个CCAutorelease的栈,每次pop都把栈顶的内存池进行处理,把栈顶内存池管理的元素release掉。至于pop在什么时候调用?看过我写的主流程(mainloop)分析可以知道——
CCDiretor在mainloop()中调用了drawScene()和CCPoolManager::sharedPoolManager()->pop()
也就是说在每帧结束后,就会进行内存的管理
总结来说,cocos2d-x内存管理的引用计数部分通过retain/release来进行计数增减,而内存池管理就通过autorelease来进行管理,在每帧结束时自动回收
C++并没有内存管理的机制,都是用new/delete来进行对象的管理(STL和boost倒是有智能指针)
现在让我来介绍 一下cocos2d-x的内存管理机制。
cocos2d-x的内存管理机制用到的类有CCObject, CCAutoreleasePool, CCPoolManager这几个类
现在先讲CCObject,CCOjbect继承于CCCopying
//CCObject.hclass CC_DLL CCCopying{public: virtual CCObject* copyWithZone(CCZone* pZone);};//CCObject.cppCCObject* 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.cppCCObject::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; //引用 = 1arr->addOjbect(object); //引用 = 2/*do something here*/object->release(); //引用 = 1,未被析构CCObject *test = arr->getObjectAtIndex(0); //可以访问arr->removeObjectAtIndex(0); //引用 = 0,析构}
通过对比很容易发现两者不一样,通过引用计数,release和delete不同,release并未等于析构,当所有对象都不持有该对象的指针时,才析构该对象,下面,我们再看看CCObject的另一个关于内存管理的函数,autorealease
//CCObject.cppCCObject* CCObject::autorelease(void){ CCPoolManager::sharedPoolManager()->addObject(this); return this;}
autorelease并未对引用进行任何的操作,只见他放进了CCPoolManager里面,这个其实就是内存池的管理者,那么我们先来看一下内存池是怎样的
//CCAutoreleasePool.hclass 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()
//CCAutoreleasePool.hclass 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.cppvoid 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进行生成- cocos2d-x源码分析::内存管理机制
- 【Cocos2d-x 3.x】内存管理机制与源码分析
- cocos2d-x内存管理机制
- cocos2d-x内存管理机制
- cocos2d-x 内存管理机制
- cocos2d-x内存管理机制
- cocos2d-x 内存管理机制
- Cocos2d-x内存管理机制
- cocos2d-x 内存管理机制
- Cocos2d-x 内存管理机制
- cocos2d-x内存管理机制剖析
- cocos2d-x内存管理机制解析
- Cocos2d-x 3.1 内存管理机制
- cocos2d-x 3.0 内存管理机制
- cocos2d-x中的内存管理机制
- cocos2d-x内存管理机制详解
- 2、COCOS2D-X内存管理机制
- Cocos2d-x 3.0 内存管理机制
- 打开jsp页面自动加载多个Action的实现方法
- broadcom corporation BCM4313 linux驱动下载地址
- Spring 任务调度
- MySQL复制表结构、建临时表
- Android编程之指定ListView的item位置
- cocos2d-x源码分析::内存管理机制
- 深入Android媒体存储服务(一):APP与媒体存储服务的交互
- Linux Shell Scripting Cookbook 学习记录1
- SQLite数据库的基本操作
- VC调用COM组件的几种方式
- Singleton模式
- php错误:You don't have permission to access / on this server.
- CentOS 6 安装配置教程
- MFC中的消息处理流程