首先我们必须说一下c++中变量的内存空间的分配问题,我们在c++中写一个类,可以在栈上分配内存空间也可以使用new在堆上分配内存空间,如果类对象是在栈上分配的内存空间,这个内存空间的管理就不是我们的事了,但如果是在堆上分配的内存空间,当然需要我们来手动的delete了!cocos2dx采用的是在堆上分配内存空间,想想看你在写程序的时候对于cocos2dx中的类是不是大多数都是通过工厂方法获得的一个指针,你见过在栈上分配内存空间的情况吗?所以问题来了,既然在堆上分配内存空间,那么如何管理这个内存空间,什么时候应该释放就是个问题了!在程序中,当我们创建了一个对象的时候,这块内存空间经常是被不同的对象引用,如果删除的早了,有对象还在引用这块内存空间那么程序必然要崩溃!所以cocos2dx引入了引用计数这个内存管理机制。
当我们在堆上分配一块内存空间的时候,这个对象的引用计数就是1,当有对象要引用这块内存空间的时候,这个引用计数就增加1,当有对象不再引用这块内存的时候引用计数就减1,当这个引用计数减为0的时候就使用delete删除掉这块内存,这样就做到了当有对象引用的时候会正常的访问这块内存,引用完毕也可以正常的回收。先来看一下如下的代码,有关引用计数的问题就会很清楚了!

//对象创建的时候引用计数被设置为1,这个是在它的构造函数中完成的,它会先调用父类CCOjbect的构造函数
//CCObject的构造函数如下所示
//CCObject::CCObject(void)
//, m_uReference(1) {}// when the object is created, the reference count of it is 1
CCSprite * sprite = new CCSprite(); CCLog("retain count:%d",sprite->retainCount()); //调用retain方法的时候引用计数增加1
sprite->retain();
CCLog("retain count:%d",sprite->retainCount()); //调用release方法的时候引用计数减一,当这个引用计数减为0的时候,在release方法中会delete掉这个对象
sprite->release();
CCLog("retain count:%d",sprite->retainCount()); //当我们调用autorelease方法的时候会调用这段代码
//CCPoolManager::sharedPoolManager()->addObject(this);
//调用autorelease方法的时候对象会被放到自动回收池中,这个自动回收池在每帧结束的时候会调用一次对象的release方法
sprite->autorelease();
CCLog("retain count:%d",sprite->retainCount());

上边的代码有一处不是很好的理解,就是大家经常说的自动回收机制,也就是上边的autorelease方法,这个方法到底为我们做了什么,有什么作用,我们需要好好的搞清楚!首先需要澄清的一个概念就是帧,我们经常的说每秒多少多少帧,其实这个帧需要多少时间不是固定的,这个需要看每帧我们需要做多少事情,如果没一帧我们需要渲染很多的东西,那这一帧执行的时间当然就会很长的,游戏显得就会很卡,这个时候每秒的帧率就会下降的,所以不是时间决定的帧率,而是帧影响的时间!这个自动回收池就是在每帧结束的时候起作用的,在游戏的每一帧都会有一个大的循环,在一帧开始之前,系统建立了一个内存回收池,在这一帧的过程中,当我们调用了autorelease方法以后,我们的对象就会放到这个内存回收池中,当一帧结束的时候这个内存回收池就会释放掉,这个时候在内存回收池中的对象就会被release一下,也就是说引用计数就会减一,如果这个时候引用计数为0,就会删除对象了。如果引用计数不为0的话对象是不会被删除的,下一帧开始的时候系统又会创建一个内存回收池,这个时候在上一次添加的对象这个时候是不会重新添加到这个内存回收池中的,在这个内存回收池中的对象是你在这一帧中调用了autorelease函数的对象。好了,内存回收池我觉的我已经说清楚了。下面我们来看一下,通常我们的代码都是怎么写的,来看看这个自动回收机制怎么就做到自动回收了!

//在create的时候调用了sprite的autorelease方法
CCSprite * sprite = CCSprite::create("HelloWorld.png");
CCLog("retain count:%d",sprite->retainCount()); //retain 1
this->addChild(sprite);
CCLog("retain count:%d",sprite->retainCount()); //retain 2

首先我们需要分析一下上边的代码,调用了create工厂方法以后,内部的实现是先new一个CCSprite的对象,这个时候引用计数加1,然后调用autorelease方法,将这个对象放到了自动回收池中,因为这一帧还没有结束,当然引用计数就还是1,所以打印的结果就是1,当我们调用addChild的时候,传入这个CCSprite对象,这个时候在当前层接受了这个对象以后会把它的引用计数加一,表明当前层正在使用这块内存空间,所以现在的retain就是2了。当这一帧结束的时候自动回收池会将对象的引用计数-1,所以现在就只有CCLayer在引用这个对象了,当CCLayer析构的时候,它会调用这个对象的release方法,这个时候当然就会删除了这个CCSprite对象了。所以什么是自动回收机制呢,自动就是在这一帧结束的时候将对象开始new的时候加的那个引用计数减掉,而让引擎中持有对象引用的其他类去管理这个对象,当持有者析构的时候就删除引用,引擎中的类负责retain和release,这个也算是自动吧!下面我们通过俩个例子来理解一下这个内存管理机制。

bool HelloWorld::init()
{ if ( !CCLayer::init() )
{
return false;
} CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback)); CCMenu* pMenu = CCMenu::create(pCloseItem, NULL); this->addChild(pMenu, ); this->m_sprite = CCSprite::create("HelloWorld.png");
CCLog("%d",this->m_sprite->retainCount()); return true;
}
//按钮的响应事件
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
CCLog("%d",this->m_sprite->retainCount());
this->m_sprite->getPosition();
}

好了,运行程序我们会发现程序崩溃了,我们来分析一下。当我们创建了CCSprite对象的时候引用计数为1,并且该对象被放到了内存回收池中,在这一帧以后就会release对象一次,这个时候引用计数为0的对象当然就被释放了,我们按下按钮去调用这个对象,内存已经释放掉了,程序能不崩溃吗?下面我们来将代码改成如下的这样,看看效果。

this->m_sprite = CCSprite::create("HelloWorld.png");
CCLog("%d",this->m_sprite->retainCount());
this->m_sprite->retain();
CCLog("%d",this->m_sprite->retainCount());

这个时候运行起来程序,在按钮的函数调用的时候你会看到输出的引用计数都是1,因为我们已经手动的retain了一下这个对象,虽然自动回收池将它release了一下,但是它的引用计数任然为1。既然我们retain了,所以在层析构的时候记得要release啊。这样内存才不会泄露!还有一个就是CCArray的例子,下面来看一下。

bool HelloWorld::init()
{
bool bRet = false;
do
{
//////////////////////////////////////////////////////////////////////////
// 父类初始化
////////////////////////////////////////////////////////////////////////// CC_BREAK_IF(! CCLayer::init());
CCSprite* bomb1 = CCSprite::create("CloseNormal.png");
CCSprite* bomb2 = CCSprite::create("CloseNormal.png");
CCSprite* bomb3 = CCSprite::create("CloseNormal.png");
CCSprite* bomb4 = CCSprite::create("CloseNormal.png");
CCSprite* bomb5 = CCSprite::create("CloseNormal.png");
CCSprite* bomb6 = CCSprite::create("CloseNormal.png"); addChild(bomb1,);
addChild(bomb2,);
addChild(bomb3,);
addChild(bomb4,);
addChild(bomb5,);
addChild(bomb6,); m_pBombsDisplayed = CCArray::create(bomb1,bomb2,bomb3,bomb4,bomb5,bomb6,NULL); this->scheduleUpdate(); bRet = true;
} while (); return bRet;
} void HelloWorld::update(ccTime dt)
{
refreshData();
} void HelloWorld::refreshData()
{
m_pBombsDisplayed->objectAtIndex()->setPosition(cpp(,));
}

其实这个原理和上边的例子是差不多的,我们创建了一个CCArray的对象,这个时候同样是没有添加到其他的层中的,所以在这一帧结束的时候就会将它的引用计数减1变成0,所以,再次使用的时候肯定就会出错了!在使用cocos2dx的内存管理的时候如果我们是通过工厂的方法创建的,并且add到了其他的层中的时候这个时候我们多数是不用担心的,但是如果你是通过new的方法创建的CCObject子类的对象,这个时候记住要在析构的时候release这个对象,如果在使用过程中你retain了对象,同样记住要release。本人总结的是,当我们调用函数传递CCObject子类对象的时候,在接受的时候我们都应该去retain一下,这样代表的是我要引用这块内存空间,什么时候你不再引用这块内存空间了,就release一下。其他的各种问题当你遇到的时候就想一下它的原理,就会明白的。最后的最后欢迎广大网友给我留言,我们共同探讨cocos2dx的问题!

cocos2dx的内存管理机制的更多相关文章

  1. [置顶] 【玩转cocos2d-x之二十】从CCObject看cocos2d-x的内存管理机制

    原创作品,转载请标明:http://blog.csdn.net/jackystudio/article/details/13765639 再看CCObject,剔除上节的拷贝相关,以及Lua脚本相关的 ...

  2. 【Cocos2d-x 3.x】内存管理机制与源码分析

    侯捷先生说过这么一句话 :  源码之前,了无秘密. 要了解Cocos2d-x的内存管理机制,就得阅读源码. 接触Cocos2d-x时, Cocos2d-x的最新版本已经到了3.2的时代,在学习Coco ...

  3. 2、COCOS2D-X内存管理机制

    在C++中.动态内存分配是一把双刃剑,一方面,直接訪问内存地址提高了应用程序的性能,与使用内存的灵活性.还有一方面.因为程序没有正确地分配与释放造成的比如野指针,反复释放,内存泄漏等问题又严重影响着应 ...

  4. cocos2d-x 3.0 内存管理机制

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

  5. 【转】cocos2dx 内存管理机制

    原文地址: http://www.zaojiahua.com/memory-management.html cocos2dx采用的是在堆上分配内存空间,想想看你在写程序的时候对于cocos2dx中的类 ...

  6. cocos2d-x之内存管理(4)

    c++的内存管理一直以来都是个问题,也有多种实现方案,比如智能指针,使用引用计数等,cocos2d-x也需要涉及到内存的管理. cocos2d-x是如何管理内存的呢? cocos2d-x的内存管理主要 ...

  7. cocos2d-js 浏览器与JSB内存管理机制的不同

    写这边文章的主要目的是为了理解使用cocos3d-js开发app时,浏览器调试与真机情况不一致的原因 一.浏览器中内存管理机制 HTML5版本运行时,整个游戏只存在JS脚本与一些必要的资源文件,这时候 ...

  8. 浅谈Linux内存管理机制

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...

  9. ARC内存管理机制详解

    ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数. ...

随机推荐

  1. I2C和LCD信号干扰的解决:硬件工程师都硬不起来,让软件工程师硬着头上

    DEMO4,LCD的clk干扰I2C,I2C无法通信. 把排针压下,去掉LCD的CLK,恢复正常.     过程: 直接跳线I2C,没问题.两排针插到一起就无法通信. 一个个的排针去除,最终找到LCD ...

  2. 初探Asp.net5

    说到Asp.net 5,确实让我有种激动的心情,微软的全力大招在一波一波的发出,也在牵动着每一个程序员的心.作为你们中的一员,在每次看到微软的新技术时,都满怀一种激动的心情,也同时希望微软在开源和跨平 ...

  3. php上传图片---初级版

    没有样式,没有淘宝的那种放大截取大小的效果,只是实现了图片上传的功能. 图片超过100k,会出现内部错误服务器错误,需要手动更改配置文件里的MaxRequestLen属性. 下面粘上代码: <? ...

  4. Object C学习笔记25-文件管理(一)

    在此篇文章中简单记录一下文件管理,在Object C中NSFileManager用于管理文件已经路径.在Object C中的文件路径可以是相对路径也可以是绝对路径.斜线“/”开头,斜线实际上就是一个目 ...

  5. java在目录中过滤文件

    package com.zh.test; import java.io.File; import java.io.FilenameFilter; public class Test2 { /** * ...

  6. 修改ssh的访问端口号

    [root@redis143 ~]# vim /etc/ssh/sshd_config 修改其中的:Port 10056 重启sshd服务 同时如果有防火墙规则的话,注意修改防火墙规则,或者关闭防火墙 ...

  7. 搭建OpenWrt开发环境(包括编译过程)

    OpenWrt是一个高度模块化.高度自动化的嵌入式linux发行版,其编译和安装过程比普通的linux发行版而言,要简单太多了.如果您是新手,您那恐惧的心大可放到肚子里,呵呵.对于新手来说最麻烦的恐怕 ...

  8. Java-HashMap和HashTable的区别

    类继承and实现上看 public class Hashtable extends Dictionary implements Map, Cloneable, java.io.Serializable ...

  9. groovy-语句

    groovy语句类似于java语句,但是在groovy中的分号”;”是可选的.比如: 1 def x = [1, 2, 3] 2 println x 3 def y = 5; def x = y +  ...

  10. hihocoder1187 Divisors

    传送门 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Given an integer n, for all integers not larger than n, f ...