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. 我用dedecms有感

    ---恢复内容开始--- 最近接了一个私单,简单的学校网站,注意,我一看上去是感觉很快,仿站,对方说这个东西你三天就能搞定啦,我也这么想的 (没经验啊) 接下来,我想都没想就用dedecms去做,之前 ...

  2. leetcode—3sum

    1.题目描述 Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find ...

  3. C# 与 VC Dll 传输信息

    考虑: 使用string类型传送: 在VC Dll中解析字符: 使用 string 类型将解析的类型传送到C#程序中: 建立VC解析的函数,提高代码可重用性

  4. [Hive - LanguageManual] Archiving for File Count Reduction

    Archiving for File Count Reduction Note: Archiving should be considered an advanced command due to t ...

  5. Spark系列(九)DAGScheduler工作原理

    以wordcount为示例进行深入分析 1  33  ) { 46        logInfo("Submitting " + tasks.size + " missi ...

  6. 超简单fedora20(linux)下JDK1.8的安装

    (博客园-番茄酱原创) 去官网下载linux版本的jdk,如果你的fedora是64位,就选择64位的jdk,jdk-8u20-linux-x64.tar.gz. 将下载好的jdk解压到当前目录下,解 ...

  7. 2016-3-25突然推送大量消息的问题及查找 -- Sangit

    起因:2016年3月25日 18:30 左右,突然接到客户投诉,说APP收到大量的任务推送消息,而且点击进去都是一些过期任务,我们将对此展开追踪,查找问题原因. 过程: 1.当时的第一反应是先查看re ...

  8. elisp语法

    http://stackoverflow.com/questions/3855862/setq-and-defvar-in-lisp defvar, let, setq的语法分析: defvar in ...

  9. 从输入 URL 到页面加载完成的过程中都发生了什么事情?

    这个问题是老生常谈的问题啦,虽然说到处百度都有的答案,还是希望自己能总结一下. 如今有很多答案,都是从硬件开始讲起,比如键盘的响应或者触屏的响应,然后CPU处理到OS的内核等等.这里不作为重点来讲,要 ...

  10. 扩展KMP题目

    hdu4333 /* 题意:字符串s[0..n-1],每次把最后一个字符放到前面,求形成的字符串比最初串分别小,相同,大于的个数 因为是为了练习扩展KMP所以肯定是扩展KMP, 为了循环方便,在后面复 ...