cocos2d-x源于cocos2d-iphone,为了与Objective-c一致,cocos2d-x也采用了引用计数与自动回收的内存管理机制。

要现实自动内存回收,需继承于cocos2d-x的根类CCObject。当然自动释放会影响性能的。

cocos2d-x中有很多静态工场方法,例如以create开头的,这些静态工场方法创建的对象都使用的autorelease,试想如果不用autorelease,

CCObject* create(){CCObject *ret = new CCObject(); return ret;}

此时函数内的引用在函数结束时就结束了,但是对方没有被释放,如果返回的ret没有被用户引用或者释放,那么就造成了内存泄露。所以加入autorelease是个不错的解决方法。

看看CCObject的这两个字段和方法:

protected:
// 引用计数
unsigned int m_uReference;
// 自动释放次数 以前是bool m_bManaged;标识是否采用自动释放
unsigned int m_uAutoReleaseCount;
public:
void release(void);
void retain(void);
CCObject* autorelease(void);
unsigned int retainCount(void);

有这么一个原则:谁引用谁retain和release,对象传值时先retain再release(避免自己给自己传值时,先release可能会释放对象),调用release方法,当引用计数为0时,就会delete此对象。

内存管理autorelease是怎么实现的呢,进入autorelease看到调用了下面这个函数:

CCPoolManager::sharedPoolManager()->addObject(this);将对象加入回收池

void CCAutoreleasePool::addObject(CCObject* pObject)
{
m_pManagedObjectArray->addObject(pObject); CCAssert(pObject->m_uReference > , "reference count should be greater than 1");
++(pObject->m_uAutoReleaseCount);
pObject->release(); // no ref count, in this case autorelease pool added.
}

函数中将对象加入管理数组中,再对自动释放计数+1,然后release使引用计数-1。

当create一个对象时,new使引用计数为1,调用autorelease后,加入回收池,然后release引用计数-1。那么此时引用计数为0吗?

答案肯定不是,如果为0,此时该对象就会被delete。cocos2d-x中的数据结构转为这种内存管理设置,如CCArray,当对array调用addObject时,就会调用retain使引用计数加1,当array调用removeObject时就会release。那么当加入回收池后,此时的这个引用归回收池所有,当一帧结束释放回收池的时候,回收池中的所有对象都会调用release。如果此时没有其他对象引用该对象,则该对象会被删除。

来看看主循环mainLoop中的调用:

    if (m_bPurgeDirecotorInNextLoop)
{
m_bPurgeDirecotorInNextLoop = false;
purgeDirector();
}
else if (! m_bInvalid)
{
drawScene(); // release the objects
CCPoolManager::sharedPoolManager()->pop();
}

每一帧结束调用sharedPoolManager()->pop()此时栈顶的回收池就被释放,

void CCPoolManager::pop()
{
if (! m_pCurReleasePool)
{
return;
} int nCount = m_pReleasePoolStack->count(); m_pCurReleasePool->clear(); if(nCount > )
{
//释放栈顶的回收池
m_pReleasePoolStack->removeObjectAtIndex(nCount-);
m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - );
}
}

此时池中的所有对象都会被release,如果没有其它的对象(场景、层、数组等)在引用他们,这些对象就会被delete。

而新一帧开始后,第一个调用autorelease的对象在内部调用getCurReleasePool()时,如果栈中没有回收池,就会push一个回收池,sharedPoolManager()->push()。

CCAutoreleasePool* CCPoolManager::getCurReleasePool()
{
if(!m_pCurReleasePool)
{
push();
}
CCAssert(m_pCurReleasePool, "current auto release pool should not be null");
return m_pCurReleasePool;
}

可以看出每一帧回收池都要建立、删除,而且添加对象进入回收池,那么性能方面当然会受到影响,当回收池中对象很多时,表现得很明显。

那么解决方法1:性能要求高的情况下不要轻易使用自动回收池。

方法2:手动释放并创建一个回收池

CCPoolManager::shardPoolManager()->push();
for(int i=; i!=n; ++i)
{
objArray[i]->autorelease();
}
CCPoolManager::shardPoolManager()->pop();

这样就不会让自动释放的对象集中在一帧结束的时候。

cocos2d-x回收池原理的更多相关文章

  1. java多线程系列(六)---线程池原理及其使用

    线程池 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知 ...

  2. Java 并发编程——Executor框架和线程池原理

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  3. Java并发——线程池原理

    "池"技术对我们来说是非常熟悉的一个概念,它的引入是为了在某些场景下提高系统某些关键节点性能,最典型的例子就是数据库连接池,JDBC是一种服务供应接口(SPI),具体的数据库连接实 ...

  4. 从JDK源码角度看线程池原理

    "池"技术对我们来说是非常熟悉的一个概念,它的引入是为了在某些场景下提高系统某些关键节点性能,最典型的例子就是数据库连接池,JDBC是一种服务供应接口(SPI),具体的数据库连接实 ...

  5. 【java】-- 线程池原理分析

    1.为什么要学习使用多线程? 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担. 线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致 ...

  6. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  7. java并发包&线程池原理分析&锁的深度化

          java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的, ...

  8. Java线程池原理解读

    引言 引用自<阿里巴巴JAVA开发手册> [强制]线程资源必须通过线程池提供,不允许在应用中自行显式创建线程. 说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销 ...

  9. 《java学习三》并发编程 -------线程池原理剖析

    阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到 ...

随机推荐

  1. 自学hadoop(三)

    1) 关于hadoop在eclipse插件.经过自己的摸爬滚打.总结一下三条.     a) 2.0或者0.23.0吧 google比较方便.其他的可以自己编译.(这个我不敢保证.我本地环境事2.1. ...

  2. markdown常用html标签

    换行 测试<br />一下 效果:测试一下 标记 <mark>测试一下</mark> 效果:测试一下 空格         测试一下 效果:        测试一下 ...

  3. mysql统计一张表中条目个数的方法

    统计一张表中条目的个通常的SQL语句是: select count(*) from tableName; #or ) from tableName; #or 统计一个列项,如ID select cou ...

  4. RabbitMQ C# 例子 -摘自网络

    //刚刚接触,如有不对还望不吝指正 public static void StartUp() { #region 前期准备工作 ConnectionFactory factory = new Conn ...

  5. MySQL 主从架构配置详解

    无论是哪一种数据库,数据的安全都是至关重要的,因此熟练掌握数据库的安全备份功能,是作为开发人员,特别是后端开发人员的一项必备技能.MySQL 数据库内建的复制功能,可以帮助我们对数据进行异地备份,读写 ...

  6. [现代程序设计]homework-03

    Homework-03 队员: 11061193 薛亚杰 11061192 周敏轩    11061190 李孟 材料阅读 我们三个人将以下材料仔细阅读,觉得十分受益.下面是我们的总结和分享: 1)代 ...

  7. 第八章、Linux 磁盘与文件系统管理

    认识 EXT2 文件系统 Linux最传统的磁盘文件系统(filesystem)使用的是EXT2这个啦!所以要了解文件系统就得要由认识EXT2开始! 而文件系统是创建在硬盘上面的,因此我们得了解硬盘的 ...

  8. 玩转轻巧型C/C++ IDE之C-Free(配置GCC、Visual C++、Borland C++编译器)

    玩转轻巧型C/C++ IDE之C-Free(配置GCC.Visual C++.Borland C++编译器) 之前在写一点简单的C/C++代码时习惯了VC++6.0,但是由于在windows7下VC6 ...

  9. internet访问局域网内部方法之----------路由器端口映射

    很多人每天都问为什么要端口映射?例如:通过路由器上网的,网站自己可以访问,但是别人就不能:输入127.0.0.1可以访问,别人还是看不到:输入localhost可以看到,但是别人就是看不到,气人啊-没 ...

  10. WEB开发框架