Cocos2d-x学习笔记(十四)CCAutoreleasePool详解
来源:互联网 发布:网络空间安全专业排名 编辑:程序博客网 时间:2024/06/04 18:57
原创文章,转载请注明出处:http://blog.csdn.net/sfh366958228/article/details/38964637
前言
之前学了那么多的内容,几乎所有的控件都要涉及内存管理类CCAutoreleasePool,所以这一次的学习笔记,我们一起来看看CCAutoreleasePool,先从CCObject的autorelease方法入手。
CCObject::autorelease
CCObject* CCObject::autorelease(void){ // 将当前对象添加到内存池中 CCPoolManager::sharedPoolManager()->addObject(this); // 将当前对象设置为已被内存池管理 m_bManaged = true; return this;}autoRelease类并不复杂,由代码中的注释可以看出主要还是CCPoolManager的操作,而这部分内容被写在了CCAutoreleasePool中,让我们一起看看吧。
CCAutoreleasePool.h
class CC_DLL CCAutoreleasePool : public CCObject{ // 保存所有添加到释放池中的对象,注意CCArray内部是通过将对象retain 然后存储起来的,应用计数会增加1 CCArray* m_pManagedObjectArray; public: CCAutoreleasePool(void); ~CCAutoreleasePool(void); // 将对象添加到自动释放池 void addObject(CCObject *pObject); // 将对象从自动释放池中移除 void removeObject(CCObject *pObject); // 将自动释放池中的对象释放掉 void clear();}; 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;};
CCAutoreleasePool.cpp
// 静态成员变量,存储整个程序中使用的CCPoolManager对象static CCPoolManager* s_pPoolManager = NULL; CCAutoreleasePool::CCAutoreleasePool(void){ //初始化队列,用以保存添加到池中的对象 m_pManagedObjectArray = new CCArray(); m_pManagedObjectArray->init();} CCAutoreleasePool::~CCAutoreleasePool(void){ CC_SAFE_DELETE(m_pManagedObjectArray);} // 将对象添加到自动释放池中void CCAutoreleasePool::addObject(CCObject* pObject){ // 将对象retain 保存到队列中 m_pManagedObjectArray->addObject(pObject); // 确保此时对象的应用计数最少是2 CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1"); // 调用对象的release方法,将引用计数减1 pObject->relearese();} void CCAutoreleasePool::removeObject(CCObject* pObject){ // 从自动释放池中移除对象,使该对象不被自动释放池管理,当然也不会自动释放,第二个参数为false,,因为addObject被没有使引用计数增加,所有这里也不能使应用计数有变化 m_pManagedObjectArray->removeObject(pObject, false);}void CCAutoreleasePool::clear(){ if(m_pManagedObjectArray->count() > 0) { //CCAutoreleasePool* pReleasePool;#ifdef _DEBUG int nIndex = m_pManagedObjectArray->count() - 1;#endif CCObject* pObj = NULL; CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj) { if(!pObj) break; pObj->m_bManaged = false; //(*it)->release(); //delete (*it);#ifdef _DEBUG nIndex--;#endif } // 移除所有的在队列中的对象,依次调用所有对象的release方法 m_pManagedObjectArray->removeAllObjects(); }} //--------------------------------------------------------------------//// CCPoolManager////-------------------------------------------------------------------- // 获取自动释放池管理者CCPoolManager* CCPoolManager::sharedPoolManager(){ if (s_pPoolManager == NULL) { s_pPoolManager = new CCPoolManager(); } return s_pPoolManager;} void CCPoolManager::purgePoolManager(){ CC_SAFE_DELETE(s_pPoolManager);} CCPoolManager::CCPoolManager(){ // 初始化自动释放池队列 m_pReleasePoolStack = new CCArray(); m_pReleasePoolStack->init(); // 当前的自动释放池为空 m_pCurReleasePool = 0;} CCPoolManager::~CCPoolManager(){ // 释放所有的自动释放池 finalize(); // we only release the last autorelease pool here m_pCurReleasePool = 0; m_pReleasePoolStack->removeObjectAtIndex(0); CC_SAFE_DELETE(m_pReleasePoolStack);} void CCPoolManager::finalize(){ // 清空自动释放池队列中的所有自动释放池 if(m_pReleasePoolStack->count() > 0) { //CCAutoreleasePool* pReleasePool; CCObject* pObj = NULL; CCARRAY_FOREACH(m_pReleasePoolStack, pObj) { if(!pObj) break; CCAutoreleasePool* pPool = (CCAutoreleasePool*)pObj; pPool->clear(); } }} void CCPoolManager::push(){ // 向自动释放池队列中添加一个新的自动释放池,将新添加的自动释放池作为当前的 // 自动释放池使用 CCAutoreleasePool* pPool = new CCAutoreleasePool(); //ref = 1 m_pCurReleasePool = pPool; m_pReleasePoolStack->addObject(pPool); //ref = 2 pPool->release(); //ref = 1} 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); }} void CCPoolManager::removeObject(CCObject* pObject){ // 从当前的自动释放池中移除对象 CCAssert(m_pCurReleasePool, "current auto release pool should not be null"); m_pCurReleasePool->removeObject(pObject);} void CCPoolManager::addObject(CCObject* pObject){ // 将对象添加到当前的自动释放池中 getCurReleasePool()->addObject(pObject);} CCAutoreleasePool* CCPoolManager::getCurReleasePool(){ // 获取当前的自动释放池 // 如果当前的自动释放池为空,说明自动释放池队列中也为空 // 通过push方法,添加新的自动释放池 if(!m_pCurReleasePool) { push(); } CCAssert(m_pCurReleasePool, "current auto release pool should not be null"); return m_pCurReleasePool;}自动释放池管理者通过pop方法,将当前自动释放池中的所有对象调用release方法进行释放,pop方法是什么时候在什么地方进行调用的呢?其实答案就在我们之前看到过的mainloop方法中:
void CCDisplayLinkDirector::mainLoop(void){ if (m_bPurgeDirecotorInNextLoop) { m_bPurgeDirecotorInNextLoop = false; purgeDirector(); } else if (! m_bInvalid) { // 绘制场景 drawScene(); // 释放自动释放池 CCPoolManager::sharedPoolManager()->pop(); }}在每一帧绘制完成之后,当前的自动释放池将会被清理,所有调用了autorelease操作的对象都会被调用release方法,减少其引用计数。如果我们创建的对象调用了autorelease,那么在稍后帧绘制之后,自动释放池被清理的时候此对象的引用计数将被减1,此对象如果没有在其他地方被retain,那么它将会被释放掉。
在对象的使用上,为保证对象能被正确的释放,需要时刻知道此对象的引用计数为多少,但是很多时候能做到这点很难,除非对所有的接口都很了解,知道其中是否对当前对象做了retain操作或者release操作,如果做不到这点,可以按照cocos2d-x框架中这样的原则去做
1、作为参数传进来的对象,如果你要长期的使用或者管理它,请 retain,不用的时候记得release
2、作为参数传进来的对象,他不是你创建或者retain的,如果你不确定他从哪里来,外面是否知道你会release掉他,请别随便调用release
3、如果你撇开自动释放池,new了一个对象而不调用autorelease,在不使用的时候直接将对象delete掉,这样的做法是很不安全的,除非你创建的对象真的只有你在使用而没有被其他对象retain。但并非代表你不能自己new和delete管理对象,因时而异。
4、创建一个新的对象,调用了对象的autorelease方法,如果想长期的使用他,请使用retain方法(包括addChild到自身,addObject到某个CCArray中),清除时使用release方法(removeChild、CCArray的removeObject等)
参考资料
1)cocos2d-x学习笔记内存管理之autorelease http://hi.baidu.com/357802636/item/7bb3e71a7838efd6be904200
0 0
- Cocos2d-x学习笔记(十四)CCAutoreleasePool详解
- Cocos2d-x学习笔记(十四)-------->粒子特效
- 我的Cocos2d-x学习笔记(二十四)CCScrollView
- cocos2d-x节点(CCAutoreleasePool.h)API
- cocos2d-x 菜鸟学习笔记十四(简单的碰撞检测 进阶篇)
- 基于cocos2d-x引擎3.9版本分析之CCAutoreleasePool篇
- Cocos2d-x学习笔记(十一)CCMenu详解
- Cocos2d-x学习笔记(十二)CCMenuItem详解
- Cocos2d-x学习笔记(十三)CCLabel详解
- Cocos2d-x结构学习(十四)CCEaseExponential、CCEaseSine、CCRepeatForever、CCCA
- Cocos2d-x学习(十四):用cocos2d-x实现MoonWarriors(暂停和恢复的实现)
- Cocos2d-x学习(十四):用cocos2d-x实现MoonWarriors(暂停和恢复的实现)
- 我的Cocos2d-x学习笔记(十四)菜单(CCMenu)、菜单项(CCMenuItem)及菜单项子类
- 【麦可网】Cocos2d-X跨平台游戏开发学习笔记---第二十四课:Cocos2D-X物理引擎之Box2D1-7
- Cocos2d-x学习笔记(二)Cocos2d-x整体框架
- Cocos2d-x 学习笔记
- Cocos2d-x学习笔记
- Cocos2d-x学习笔记
- window对象的弹窗方法、将字符转换为数据、判断变量类型
- mysql常用的管理命令myql
- list使用与简单实现
- Sublime Text 手冊
- centos服务器安装配置ntp服务器
- Cocos2d-x学习笔记(十四)CCAutoreleasePool详解
- poj2840
- 时间序列一般概念
- 点击爱心跳转问题。ajax,跳转到页面顶部
- 滚动视图(UIScrollView)无限无缝左右切换图片,自动顺序加逆序循环播放图片
- stack使用与简单实现
- selector的用法
- 【leetcode】Divide Two Integers
- 李开复:算法的力量 (完整版)