原创文章,转载请注明出处: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

Cocos2d-x学习笔记(十四)CCAutoreleasePool具体解释的更多相关文章

  1. python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例

    python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...

  2. (C/C++学习笔记) 十四. 动态分配

    十四. 动态分配 ● C语言实现动态数组 C语言实现动态数组,克服静态数组大小固定的缺陷 C语言中,数组长度必须在创建数组时指定,并且只能是一个常数,不能是变量.一旦定义了一个数组,系统将为它分配一个 ...

  3. SharpGL学习笔记(十四) 材质:十二个材质球

    材质颜色 OpenGL用材料对光的红.绿.蓝三原色的反射率来近似定义材料的颜色.象光源一样,材料颜色也分成环境.漫反射和镜面反射成分,它们决定了材料对环境光.漫反射光和镜面反射光的反射程度.在进行光照 ...

  4. 【转】angular学习笔记(十四)-$watch(1)

    本篇主要介绍$watch的基本概念: $watch是所有控制器的$scope中内置的方法: $scope.$watch(watchObj,watchCallback,ifDeep) watchObj: ...

  5. angular学习笔记(十四)-$watch(1)

    本篇主要介绍$watch的基本概念: $watch是所有控制器的$scope中内置的方法: $scope.$watch(watchObj,watchCallback,ifDeep) watchObj: ...

  6. Java学习笔记十四:如何定义Java中的类以及使用对象的属性

    如何定义Java中的类以及使用对象的属性 一:类的重要性: 所有Java程序都以类class为组织单元: 二:什么是类: 类是模子,确定对象将会拥有的特征(属性)和行为(方法): 三:类的组成: 属性 ...

  7. MYSQL进阶学习笔记十四:MySQL 应用程序优化!(视频序号:进阶_32)

    知识点十五:MySQL 的应用程序优化(32) 一.访问数据库采用连接池 把连接当做对象或设备,统一放在‘连接池’里.凡是需要访问数据库的地方都从连接池里取连接 二.采用缓存减少对于MySQL的访问: ...

  8. Swift学习笔记十四:构造(Initialization)

         类和结构体在实例创建时,必须为全部存储型属性设置合适的初始值. 存储型属性的值不能处于一个未知的状态.     你能够在构造器中为存储型属性赋初值,也能够在定义属性时为其设置默认值.下面章节 ...

  9. JavaScript权威设计--Window对象之Iframe(简要学习笔记十四)

    1.Window对象属性的文档元素(id) 如果在HTML文档中用id属性来为元素命名,并且如果Window对象没有此名字的属性,Window对象会赋予一个属性,它的名字是id属性的值,而他们的值指向 ...

  10. Oracle学习笔记十四 内置程序包

    扩展数据库的功能 为 PL/SQL 提供对 SQL 功能的访问 用户 SYS 拥有所有程序包 是公有同义词 可以由任何用户访问 一些内置程序包 程序包名称 说明 STANDARD和DBMS_STAND ...

随机推荐

  1. (一)React再学习

    新公司的技术栈是React,虽然之前对react大概过了一遍,但是自己没有实际落地过项目 再学习一遍react: 一.react全家桶 ·create-react-app ·组件化思维 ·JSX ·开 ...

  2. 浏览器解析,HTTP/HTTPS、TCP/IP、WebSocket协议

    浏览器相关 浏览器对同一个域名有连接数限制,大部分是 6. 浏览器指的是 Chrome.Firefox,而浏览器内核则是 Blink.Gecko,浏览器内核只负责渲染,GUI 及网络连接等跨平台工作则 ...

  3. POJ-1511 Invitation Cards 往返最短路 邻接表 大量数据下的处理方法

    题目链接:https://cn.vjudge.net/problem/POJ-1511 题意 给出一个图 求从节点1到任意节点的往返路程和 思路 没有考虑稀疏图,上手给了一个Dijsktra(按紫书上 ...

  4. [原创]关于javax.servlet.ServletException: File [/loginController/getVerifCode.jsp] not found异常 解决方案

    如果前台可以访问 后台并且有数据进行响应,那么一下方案也许可以帮到你... 修改前: 出现异常 javax.servlet.ServletException: File [/loginControll ...

  5. react-native 编译报错: undefined is not an object (evaluating '_react2.PropTypes.func')

    情况通报: 因为是我的二维码模块报错,提示报错代码如下 重要信息是下面的红色字体部分(Android 模拟器红屏) undefined is not an object (evaluating '_r ...

  6. H3C S5130交换机堆叠操作

    配置过程中注意事项: 1.最好提前定义好IRF的主从设备,可通过IRF优先级进行定义,越大越优 2.一定要在使能IRF之前就保存配置(因为使能过程中,会出现设备重启的情况,如果设备重启后配置丢失,会导 ...

  7. mysql给某字段随机赋特定范围的整数值

    [引] mysql中随机生成一些范围内的整数有时候是很有用的,用到了2个函数 1.floor(f) 返回一个不大于f的最大整数 2.rand(),rand(n) 返回一个随机浮点值 v ,范围在 0  ...

  8. Java8 Lamdba表达式 002

    本篇将讲述lamdba表达式的排序,本例包括一个Player对象的集合[稍后定义],通过每一个player的分数高低对列表的player进行排序.类定义001例如以下 public class Sor ...

  9. 使用AFNetworking第三方下载类

    AFNetworking 眼下使用比較多得一个下载库 眼下一直在维护更新,使用的是很easy 不须要加入不论什么关联的库  1.带block形式 内部是任务队列进行下载  就是对operation的一 ...

  10. 【POJ 2750】 Potted Flower(线段树套dp)

    [POJ 2750] Potted Flower(线段树套dp) Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4566   ...