【转】cocos2dx 内存管理机制
原文地址: http://www.zaojiahua.com/memory-management.html
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一下。其他的各种问题当你遇到的时候就想一下它的原理,就会明白的。
对于手动内存管理,我们需遵循new/release,retain/release配对使用的原则,谁new,谁release;谁retain,谁release。new出来的对象如果是要加入到cocos2dx集合中,添加完后一定不要忘记release,集合类已经为你retain了对象,你还是要为你的new配对release一次,否则当这个对象从集合中移除时不会被正确销毁。
【转】cocos2dx 内存管理机制的更多相关文章
- 2、COCOS2D-X内存管理机制
在C++中.动态内存分配是一把双刃剑,一方面,直接訪问内存地址提高了应用程序的性能,与使用内存的灵活性.还有一方面.因为程序没有正确地分配与释放造成的比如野指针,反复释放,内存泄漏等问题又严重影响着应 ...
- cocos2dx内存管理机制
参考以下两篇文章 http://blog.csdn.net/ring0hx/article/details/7946397 http://blog.csdn.net/whuancai/article/ ...
- cocos2dx 内存管理机制
持续更新吧. 刚开始看了一些. 一,CCObject 提供引用计数 1,unsinged int m_uReference; //此为CCOBject的引用计数,初始化为 1: new CCObje ...
- cocos2d-x内存管理
Cocos2d-x内存管理 老师让我给班上同学讲讲cocos2d-x的内存管理,时间也不多,于是看了看源码,写了个提纲和大概思想 一. 为什么需要内存管理 1. new和delete 2. 堆上申 ...
- 【Cocos2d-x 3.x】内存管理机制与源码分析
侯捷先生说过这么一句话 : 源码之前,了无秘密. 要了解Cocos2d-x的内存管理机制,就得阅读源码. 接触Cocos2d-x时, Cocos2d-x的最新版本已经到了3.2的时代,在学习Coco ...
- cocos2dx的内存管理机制
首先我们必须说一下c++中变量的内存空间的分配问题,我们在c++中写一个类,可以在栈上分配内存空间也可以使用new在堆上分配内存空间,如果类对象是在栈上分配的内存空间,这个内存空间的管理就不是我们的事 ...
- Cocos2d-x 3.1 内存管理机制
Cocos2d-x使用的内存管理方式是引用计数.引用计数是一种非常有效的机制.通过给每个对象维护一个引用计数器,记录该对象当前被引用的次数.当对象添加一次引用时,计数器加1:而对象失去一次引用时.计数 ...
- cocos2d-x 3.0 内存管理机制
***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...
- cocos2d-x内存管理(见解)
cocos2d-x 延续了cocos2d 和OC的引用计数的内存管理机制! 下面我们来看看CCDriectro类 CCPoolManager::sharedPoolManager()->push ...
随机推荐
- T1229 数字游戏 codevs
http://codevs.cn/problem/1229/ 题目描述 Description Lele 最近上课的时候都很无聊,所以他发明了一个数字游戏来打发时间. 这个游戏是这样的,首先,他拿出 ...
- Jetson TK1 四:重新安装系统(刷机)
转载:http://blog.sina.com.cn/s/blog_bab3fa030102vk21.html Jetson TK1是NVIDIA基于Tegra K1开发的一块低成本开发板,板载一块T ...
- 2019年春招Android方向腾讯电话面试
第一问:TCP与UDP的区别 参考答案: 1.基于连接与无连接 2.TCP要求系统资源较多,UDP较少: 3.UDP程序结构较简单 4.流模式(TCP)与数据报模式(UDP); 5.TCP保证数据正确 ...
- google 集群计算的3大基础设施
1. GFS 分布式文件系统 2. map-reduce 分布式计算框架 3. bigtable 海量key-value的存储 (开源实现:Hypertable)
- 使用RPi-Monitor监控、统计Guitar的运行状态
前言 之前发在ickey社区上的一系列文章: 犹抱琵琶半遮面,无人知是荔枝来--unboxing & interview 一.二.三 葡萄美酒夜光杯,巧妇难为无米炊--资料与社区 一支穿云箭, ...
- RBtree插入跟删除图解代码
一.红黑树的简单介绍 RBT 红黑树是一种平衡的二叉查找树.是一种计算机科学中经常使用的数据结构,最典型的应用是实现数据的关联,比如map等数据结构的实现. 红黑树有下面限制: 1. 节 ...
- zedboard中OLED源码
#include <stdio.h> #include "platform.h" #include "xil_types.h" #include & ...
- 软件系统架构 https://www.lanhusoft.com/Article/349.html
跟蓝狐学习Nop--NopCommerce源码架构详解专题目录 Posted By : 蓝狐 Updated On : 2018-04-16 14:46 我们承接以下nop相关的业务,欢迎联系我们. ...
- Intel Chipsets
http://en.wikipedia.org/wiki/Chipset Chipset From Wikipedia, the free encyclopedia A chipset is ...
- @Transactional 无效的解决方案
1 .在需要事务管理的地方加@Transactional 注解.@Transactional 注解可以被应用于接口定义和接口方法.类定义和类的 public 方法上 . 2 . @Transactio ...