cocos2d-x回收池原理
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回收池原理的更多相关文章
- java多线程系列(六)---线程池原理及其使用
线程池 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知 ...
- Java 并发编程——Executor框架和线程池原理
Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...
- Java并发——线程池原理
"池"技术对我们来说是非常熟悉的一个概念,它的引入是为了在某些场景下提高系统某些关键节点性能,最典型的例子就是数据库连接池,JDBC是一种服务供应接口(SPI),具体的数据库连接实 ...
- 从JDK源码角度看线程池原理
"池"技术对我们来说是非常熟悉的一个概念,它的引入是为了在某些场景下提高系统某些关键节点性能,最典型的例子就是数据库连接池,JDBC是一种服务供应接口(SPI),具体的数据库连接实 ...
- 【java】-- 线程池原理分析
1.为什么要学习使用多线程? 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担. 线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致 ...
- Java 并发编程——Executor框架和线程池原理
Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...
- java并发包&线程池原理分析&锁的深度化
java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的, ...
- Java线程池原理解读
引言 引用自<阿里巴巴JAVA开发手册> [强制]线程资源必须通过线程池提供,不允许在应用中自行显式创建线程. 说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销 ...
- 《java学习三》并发编程 -------线程池原理剖析
阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到 ...
随机推荐
- 多校5 1001 HDU5781 ATM Mechine 记忆化搜索+概率
// 多校5 1001 HDU5781 ATM Mechine // http://acm.hdu.edu.cn/search.php?field=problem&key=2016+Multi ...
- oc_转_NSArrray 和 NSMutableArrray
Objective C 中除了可以使用C中的基本数组外,如 int[5];,char word[] = {‘a’, 'b’, 'c’};,Foundation 还提供了 NSArray 类.Found ...
- 我的web前端修炼之路从此开始
看过一篇文章,上面说过要想学习一门新技术,从什么时候开始都是不晚的.但对于一名大四的学生,只会一点简单的网页架构,只懂得HTML,CSS,JavaScript简单的一点皮毛,却怎么也说不过去.但也是这 ...
- Base64编解码(C++版)
#include <string> using namespace std; class ZBase64 { public: /*编码 DataByte [ ...
- C#的dll被其他程序调用时,获取此dll正确的物理路径
当C# dll被其他程序调用时,用Application.StartupPath获取的dll路径并不一定是此dll的物理路径,有可能是调用程序的路径. 以下方法或者能够获取dll正确的物理路径(未经过 ...
- JavaScript随笔记(一)基础概念以及变量类型
一.JavaScript中的基础概念 1.defer属性 一般我们在引用外部js文件的时候往往是将引用文件的位置放在标签当中,比如那么在标签中引入多个js文件时,浏览器会按照引入顺序加载执行这些引入的 ...
- Unity3D之Mecanim动画系统学习笔记(七):IK(反向动力学)动画
什么是IK? IK(Inverse Kinematics)即反向动力学,即可以使用场景中的各种物体来控制和影响角色身体部位的运动,一般来说骨骼动画都是传统的从父节点到子节点的带动方式(即正向动力学), ...
- 多浏览器兼容flv视频播放HTML
HTML: <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http: ...
- 教你50招提升ASP.NET性能(二十六):对于开发人员的数据库性能技巧
Database Performance Tips for Developers对于开发人员的数据库性能技巧 As a developer you may or may not need to go ...
- UVa 11111 Generalized Matrioshkas
嵌套玩具, 要求外层玩具的尺寸比内层玩具尺寸的和要大. 每一个玩具由一个负数与相应的正数表示, 在这两数之间的部分即为此玩具内部的玩具. 要求判断一串输出的数字是否能组成一个合法的玩具. 一个合法的玩 ...