(20)Cocos2d-x中的引用计数(Reference Count)和自动释放池(AutoReleasePool)
引用计数
引用计数是c/c++项目中一种古老的内存管理方式。当我8年前在研究一款名叫TCPMP的开源项目的时候,引用计数就已经有了。
iOS SDK把这项计数封装到了NSAutoreleasePool中。所以我们也在Cocos2d-x中克隆了一套CCAutoreleasePool。两者的用法基本上一样,所以假如你没有涉及过ios开发,你可以看看苹果官方文档NSAutoreleasePool Class Reference。
CCAutoreleasePool
Cocos2d-x的CCAutoreleasePool和cocoa的NSAutoreleasePool有相同的概念和API,但是有两点比较重要的不同:
CCAutoreleasePool不能被开发者自己创建。Cocos2d-x会为我们每一个游戏创建一个自动释放池实例对象,游戏开发者不能新建自动释放池,仅仅需要专注于release/retain cocos2d::CCObject的对象。
- CCAutoreleasePool不能被用在多线程中,所以假如你游戏需要网络线程,请仅仅在网络线程中接收数据,改变状态标志,不要这个线程里面调用cocos2d接口。下面就是原因:
CCAutoreleasePool的逻辑是,当你调用object->autorelease(),object就被放到自动释放池中。自动释放池能够帮助你保持这个object的生命周期,直到当前消息循环的结束。在这个消息循环的最后,假如这个object没有被其他类或容器retain过,那么它将自动释放掉。例如,layer->addChild(sprite),这个sprite增加到这个layer的子节点列表中,他的声明周期就会持续到这个layer释放的时候,而不会在当前消息循环的最后被释放掉。
这就是为什么你不能在网络线层中管理CCObject生命周期,因为在每一个UI线程的最后 ,自动释放对象将会被删除,所以当你调用这些被删掉的对象的时候,你就会遇到crash。
CCObject::release(), retain() and autorelease()
简而言之,这只有两种情况你需要调用release()方法
你new一个cocos2d::CCObject子类的对象,例如CCSprite,CCLayer等。
- 你得到cocos2d::CCObject子类对象的指针,然后在你的代码中调用过retain方法。
下面例子就是不需要调用retain和release方法:
CCSprite* sprite = CCSprite::create("player.png");
这里就没有更多的代码用于sprite了。但是请注意sripte->autorelease()已经在CCSprite::create(const char*)方法中被调用了,因此这个sprite将在消息循环的最后自动释放掉。
使用静态构造函数
CCSprite::create(“player.png”)是一个使用静态构造函数的例子。所以在Cocos2d-x中所有的类,除了单例,都提供了静态构造函数,这些静态构造函数包含下面4项操作:
新建一个对象
调用object->init(…)
假如初始化成功,例如,成功的找到纹理文件,那么接下来将会调用object->autorelease()。
- 返回这个已经被标记了autorelease的对象。
所有CCAsdf::createWithXxxx(…)这种类型的函数都有以上这些方式。
在Cocos2d-x v1.x或者更早版本里,这些方式是:
CCSprite* sprite = CCSprite::spriteWithTexture(...)
使用这些静态构造函数,你不需要关心“new”, “delete”和“autorelease”,仅仅关心object->retain() 和 object->release()。
一个错误的例子
一个开发者报告了一个使用CCArray 并导致crash的例子
bool HelloWorld::init()
{
bool bRet = false;
do
{
//////////////////////////////////////////////////////////////////////////
// super init first
//////////////////////////////////////////////////////////////////////////
CC_BREAK_IF(! CCLayer::init());
//////////////////////////////////////////////////////////////////////////
// add your codes below...
//////////////////////////////////////////////////////////////////////////
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,1);
addChild(bomb2,1);
addChild(bomb3,1);
addChild(bomb4,1);
addChild(bomb5,1);
addChild(bomb6,1);
m_pBombsDisplayed = CCArray::create(bomb1,bomb2,bomb3,bomb4,bomb5,bomb6,NULL);
//m_pBombsDisplayed 是在头文件中被定义为一个 protected 变量.
// <--- 我们应该添加在这里m_pBombsDisplayed->retain()方法来防止在HelloWorld::refreshData()中crash。
this->scheduleUpdate();
bRet = true;
} while (0);
return bRet;
}
void HelloWorld::update(ccTime dt)
{
refreshData();
}
void HelloWorld::refreshData()
{
m_pBombsDisplayed->objectAtIndex(0)->setPosition(cpp(100,100));
}
他的错误是m_pBombsDisplayed是使用CCArray::create(…)创建的,这种创建方式是静态构造方式,这个数组被标记了autorelease。
所以这个数组会在当前消息循环的最后被CCAutoreleasePool释放掉。
当后面的消息循环调用HelloWorld::update(ccTime)的时候,m_pBombsDisplayed已经是一个野指针了,这就将引起崩溃。
为了修复这个崩溃情况,我们需要增加m_pBombsDisplayed->retain()在 m_pBombsDisplayed =CCArray::create(…);之后, 并且在 HelloWorld::~HelloWorld() 的析构函数中调用m_pBombsDisplayed->release()。
(20)Cocos2d-x中的引用计数(Reference Count)和自动释放池(AutoReleasePool)的更多相关文章
- OC中对象元素的引用计数 自动释放池的相关概念
OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc] view plaincopy 1. // 2. / ...
- Objective-C中的引用计数
导言 Objective-C语言使用引用计数来管理内存,也就是说,每个对象都有个可以递增或递减的计数器.如果想使某个对象继续存活,那就递增其引用计数:用完了之后,就递减其计数.计数为0,就表示没人关注 ...
- swift内存管理中的引用计数
在swift中,每一个对象都有生命周期,当生命周期结束会调用deinit()函数进行释放内存空间. 观察这一段代码: class Person{ var name: String var pet: P ...
- OC_内存管理(二)对象复制、循环引用问题、自动释放池
循环调用: 1.循环引用的问题 两个对象A.B,有可能会出现特殊情况:A中包含B的实例变量:B中也包含A的实例变量,如果这两个实例变量都是强引用(A有着B的实例变量所有权,B也有A的实例变量所有权 ...
- Objective-C中的自动释放池
自动释放池块@autoreleasepool 自动释放池块在MRC和ARC下都可以使用.在MARC下,为了将自动释放池块内部的变量放入自动释放池,需要手动调用autorelease方法:在ARC下,只 ...
- OC学习篇之---数组对象的引用计数问题和自动释放池的概念
之前一片文章中我们介绍了OC中的两个关键字@property和@synthesize的使用的使用: http://blog.csdn.net/jiangwei0910410003/article/de ...
- juce中的引用计数
这个类提供了最基本的引用计数管理,界面库中,经常都需要消息发送,而带来的后果就是不知道消息中包含的对象是否还存在,如果不能很好管理的话就容易出现访问销毁了的对象这样的情况,所以,juce的界面无素也基 ...
- Python中的引用计数法
目录 引用计数法 增量操作 计数器溢出的问题 减量操作 终结器 插入计数处理 引用计数法 增量操作 如果对象的引用数量增加,就在该对象的计数器上进行增量操作.在实际中它是由宏Py_INCREF() 执 ...
- java中垃圾回收机制中的引用计数法和可达性分析法(最详细)
首先,我这是抄写过来的,写得真的很好很好,是我看过关于GC方面讲解最清楚明白的一篇.原文地址是:https://www.zhihu.com/question/21539353
随机推荐
- jQuery中animate()的方法以及$("body").animate({"scrollTop":top})不被Firefox支持问题的解决
转载请注明出处:http://blog.csdn.net/dongdong9223/article/details/50846678 本文出自[我是干勾鱼的博客] jQuery中animate()的方 ...
- PHP - PhpStorm 快捷键大全 PhpStorm 常用快捷键和配置(转)
原文地址:http://www.cr173.com/html/66775_1.html PhpStorm 是 JetBrains 公司开发的一款商业的 PHP 集成开发工具,PhpStorm可随时帮助 ...
- laravel 发送邮件
1)邮件配置(config/mail.php 配置文件) MAIL_DRIVER 邮箱驱动,laravel 支持 "smtp", &qu ...
- vs2010中使用luabind
第一部分:在vs2010中生成luabind静态库和动态库 一.前期准备 1.安装boost 下载boost并解压到 D:\mylua\boost_1_56_0,进入 D:\mylua\boost_1 ...
- c++虚函数[转]
C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父 ...
- JSP自定义标签开发入门《转》
JSP自定义标签开发入门 一般情况下开发jsp自定义标签需要引用以下两个包 import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; ...
- 2.实现官网环境, 搭建HTTP服务器
1.建立 HTTP 服务器 Node.js 是为网络而诞生的平台,但又与 ASP.PHP 有很大的不同,究竟不同在哪里呢?如果你有 PHP 开发经验,会知道在成功运行 PHP 之前先要配置一个功能强大 ...
- Egret的一些性能优化
Egret的性能优化不知道在哪里啊,主要参考Laya的性能优化,都差不多 一.性能统计面板 index.html页面设置data-show-fps=true打开性能面板 性能统计面板说明 Egret没 ...
- 【BZOJ4559】[JLoi2016]成绩比较 动态规划+容斥+组合数学
[BZOJ4559][JLoi2016]成绩比较 Description G系共有n位同学,M门必修课.这N位同学的编号为0到N-1的整数,其中B神的编号为0号.这M门必修课编号为0到M-1的整数.一 ...
- Unity3D笔记十一 定制导航菜单栏
一.定制导航栏 Unity导航菜单栏位于游戏引擎界面的顶部,其中有很多选项且含义各不相同.Unity为开发者提供了导航菜单栏的程序接口,使用代码可以动态添加菜单栏中的选项以及子项 using Unit ...