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的这两个字段和方法:

  1. protected:
  2. // 引用计数
  3. unsigned int m_uReference;
  4. // 自动释放次数 以前是bool m_bManaged;标识是否采用自动释放
  5. unsigned int m_uAutoReleaseCount;
  6. public:
  7. void release(void);
  8. void retain(void);
  9. CCObject* autorelease(void);
  10. unsigned int retainCount(void);

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

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

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

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

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

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

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

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

  1. if (m_bPurgeDirecotorInNextLoop)
  2. {
  3. m_bPurgeDirecotorInNextLoop = false;
  4. purgeDirector();
  5. }
  6. else if (! m_bInvalid)
  7. {
  8. drawScene();
  9.  
  10. // release the objects
  11. CCPoolManager::sharedPoolManager()->pop();
  12. }

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

  1. void CCPoolManager::pop()
  2. {
  3. if (! m_pCurReleasePool)
  4. {
  5. return;
  6. }
  7.  
  8. int nCount = m_pReleasePoolStack->count();
  9.  
  10. m_pCurReleasePool->clear();
  11.  
  12. if(nCount > )
  13. {
  14. //释放栈顶的回收池
  15. m_pReleasePoolStack->removeObjectAtIndex(nCount-);
  16. m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - );
  17. }
  18. }

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

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

  1. CCAutoreleasePool* CCPoolManager::getCurReleasePool()
  2. {
  3. if(!m_pCurReleasePool)
  4. {
  5. push();
  6. }
  7. CCAssert(m_pCurReleasePool, "current auto release pool should not be null");
  8. return m_pCurReleasePool;
  9. }

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

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

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

  1. CCPoolManager::shardPoolManager()->push();
  2. for(int i=; i!=n; ++i)
  3. {
  4. objArray[i]->autorelease();
  5. }
  6. 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. [转]JQuery.Ajax之错误调试帮助信息

    下面是Jquery中AJAX参数详细列表: 参数名 类型 描述 url String (默认: 当前页地址) 发送请求的地址. type String (默认: "GET") 请求 ...

  2. [Hive - LanguageManual] Create/Drop/Grant/Revoke Roles and Privileges / Show Use

    Create/Drop/Grant/Revoke Roles and Privileges Hive Default Authorization - Legacy Mode has informati ...

  3. 分类算法之朴素贝叶斯分类(Naive Bayesian Classification)

    1.什么是分类 分类是一种重要的数据分析形式,它提取刻画重要数据类的模型.这种模型称为分类器,预测分类的(离散的,无序的)类标号.例如医生对病人进行诊断是一个典型的分类过程,医生不是一眼就看出病人得了 ...

  4. Windwos Server 2008: 当网卡有多个IP地址时,如何指定缺省地址?

    这实际是一个当应用向外发起连接时,协议栈对源IP地址的选择问题.如果你的应用没有显式绑定一个本地地址,协议栈会选择一个"最佳"的本地地址来使用. 从 Vista 之后这个选择策略发 ...

  5. [JS代码]如何判断ipad或者iphone是否为横屏或者竖屏 - portrait或者landscape

    //判断横屏或者竖屏 function orient() { //alert('gete'); if (window.orientation == 0 || window.orientation == ...

  6. 【转】Maven实战(一)---Maven Build--缺少Jar包

    原博文出于: http://blog.csdn.net/liutengteng130/article/details/41426955   感谢! 新建的Maven项目,在build的时候总是打包失败 ...

  7. snprintf 返回值

    在平时写代码的过程中,我一个推荐带有n系列的字符串函数,如 strcat ->strncat sprintf->snprintf 我们有类似的一个函数 void dump_kid(std: ...

  8. oracle中DECODE与CASE的用法区别

    对于CASE与DECODE其实并没有太多的区别,他们都是用来实现逻辑判断.Oracle的DECODE函数功能很强,灵活运用的话可以避免多次扫描,从而提高查询的性能.而CASE是9i以后提供的语法,这个 ...

  9. POJ 3268 Silver Cow Party (最短路dijkstra)

    Silver Cow Party 题目链接: http://acm.hust.edu.cn/vjudge/contest/122685#problem/D Description One cow fr ...

  10. 深度剖析WordPress主题结构(转)

    利用强大的技术,可以把基于wordpress的网站做成各种各样的形式,这除了要求wordpress主题开发人员精通html,PHP,JS,CSS等技术,还需要开发者掌握WordPress主题的框架. ...