文档章节

【深入Cocos2d-x】探索Cocos2d-x中的内存管理-引用计数和自动释放池

王选易
 王选易
发布于 2013/05/27 19:58
字数 923
阅读 3.7K
收藏 26

#深入Cocos2d-x-探索Cocos2d-x中的内存管理-引用计数和自动释放池

###引用计数(Reference Count)

引用计数是一种在C++中相当古老的内存管理方法,ios中将这种机制包括在NSAutoreleasePool中。所有我们在Cocos2d-x中也有个相似的东西,叫CCAutoreleasePool,用处基本上一样,详细请看:NSAutoreleasePool Class Reference

###CCAutoRealeasePool

CCAutoRealeasePool与NSAutoreleasePool有着相同的概念和架构,但有两个重要区别:

  1. CCAutoreleasePool不能嵌套,所以每个cocoss2d-x的游戏实例中仅能有一个,开发者不能创建新的CCAutoreleasePool,而只是注意CCOject的释放和增加引用计数(realease/retain)就可以了
  2. CCAutoreleasePool不能在多线程中使用 。所以如果你的游戏需要一个网络线程,请仅仅接收数据或者改变网络中的状态值,不要调用其中的Cocos2d接口。

CCAutoreleasePool的逻辑是这样的:当你调用object->autorealease()这个方法时,这个object就被放在了CCAutoreleasePool中,这个计数池能帮你拿着这个object,想一个管家一样的保存到当前message loop的结尾。等到了当前message loop的结尾如果这个object没有被任何一个class或者container持有(retain)的话,它就被自动释放出来。例如:layer->addChild(sprite),这个sprite被加到layer的children list中去,那么它的生命周期就一直保持到这个layer被释放的时候,而不是当前message loop的结尾就被释放。

所以啦,你就不能在网络线程中管理CCObject啦:在每个UI线程结束时,autorealease object就会被删除掉,当你调用这些已经被删除掉的对象的指针的话,game就会崩掉

###CCObject::release(), retain() and autorelease()

总而言之,有两种情况你需要调用 ->realease()方法

  1. 当你通过new的方式创建一个CCObject时
  2. 当你得到一个CCObject的指针,然后在代码里调用“retain”方法

下面是一个例子,他不需要realease()

CCSprite* sprite = CCSprite::create("player.png");

如果你看了源码的话,你会发现在create方法里CCSprite已经调用了autorealease

###使用静态构造方法

CCSprite::create("player.png") 就是用了静态构造方法. 在Cocos2d-x中的所有类, 除了单件, 都提供了这种create方法,在其中包含了四个操作:

  1. new an object
  2. call object->init(...)
  3. if init success, e.g. find the texture file successfully, it will call object->autorelease();
  4. return the object marked as autorelease.

所有的 CCAsdf::createWithXxxx(...) 类型的函数都™一个行为

在使用create方法时,你不用考虑new,delete,autorealease之类的事,只要专注于这一对:object->retain() 和 object->release()

###一个错误的实例

一个开发者弄CCArray时弄崩了

<!-- lang: cpp -->
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 is defined in the header as a protected var.
        // <--- We should add m_pBombsDisplayed->retain() here to avoid crashing in HelloWorld::refreshData()

        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是由create方法创建的,他被标记为autorealease,

所以在message loop结束时CCArray就被删除了

当随后的message loop调用 HelloWorld::update(ccTime)时,m_pBombsDisplayed已经是null了,所以解决办法是在create方法后加上retain,在析构方法中加realease

翻译原文请点击这里

© 著作权归作者所有

王选易

王选易

粉丝 99
博文 20
码字总数 20066
作品 3
南京
程序员
私信 提问
加载中

评论(3)

王选易
王选易 博主
现在再看这篇文章又对message loop有了新的理解。
z
zkboos
cjk
jsxqf
jsxqf
沙发;
深入理解 Cocos2d-x 内存管理

如果 Cocos2d-x 内存管理浅说 做为初步认识,而 Cocos2d-x 内存管理的一种实现做为进阶使用,那么本文将详细的分析一下 Cocos2d-x 的内存管理的设计实现和原理。知其然,知其所以然 ~或者说:...

xuhong
2019/09/29
0
0
Cocos2d-x的对象创建与内存管理

1. cocos2d-x对象的创建 cocos2d-x中的对象都继承根节点CCNode,这些对象都是创建在堆上,通过指针引用。cocos2d-x对象的创建方法有两种: 1).通过new创建一个未初始化的对象,并调用init方法...

xiax_xia
2018/03/06
0
0
Cocos2d-x开发中Ref内存管理

Ref类是Cocos2d-x根类,Cocos2d-x中的很多类都派生自它,例如,我们熟悉的节点类Node也派生自Ref。我们介绍Ref内存管理。 内存引用计数 Ref类设计来源于Cocos2d-iphone的CCObject类,在Cocos...

智捷课堂
2014/11/04
46
0
cocos2dx3.0的内存管理机制

cocos2d-x中的内存管理机制可以看成给予智能指针的一个变体,但它同时是程序员进而一项实用垃圾回收机制那样不需要声明智能指针 1,引用计数 cocos2d中所有的对象几乎都集成自Ref基类。Ref基...

亮亮同学
2019/01/19
0
0
cocos2d-x学习笔记18:内存管理01:概述

一、概述 cocos2d-x最初移植自cocos2d的objective C版本。因此,在内存管理上,使用了和NSObject类似的引用计数器方法,相关接口放置在CCObject类中。 二、引用计数器——手动管理内存 CCOb...

技术小胖子
2017/11/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何替换SQL Server表列中的字符串

我有一个表( SQL Sever )引用路径( UNC或其他),但现在路径将会改变。 在路径列中,我有很多记录,我只需要更改路径的一部分,而不是整个路径。 我需要在每条记录中将相同的字符串更改为...

javail
14分钟前
17
0
>>>和>>之间的区别

Java中>>>和>>运算符之间有什么区别? #1楼 阅读更多有关按位和移位运算符的信息 >> Signed right shift>>> Unsigned right shift 位模式由左操作数给出,移位位置的数量由右操作......

技术盛宴
30分钟前
27
0
java设计模式之代理模式

代理模式: 静态代理 动态代理 静态代理:让代理类替代被被代理类完成一些“非业务”代码,核心业务代码还是交给代理者自己完成。 静态代理模式写法: 主题接口 被代理类 代理类 package cn...

a伟正是在下
32分钟前
24
0
dubbo和zookeeper的启动

1 、需要这四个 tomcat dubbo-admin zookeeper java 2 开启zookeeper ./zkServer.sh 3 在tomcat中配置开启dubbo-admin的线程 4 开启tomcat ./startup.sh 5 结果...

南桥北木
39分钟前
43
0
使用docker-compose将gitlab10.8.2迁移至docker并升级到最新版本(12.8.1)

备份数据 执行备份指令:gitlab-rake gitlab:backup:create 默认情况会在 /var/opt/gitlab/backups/ 生成一个tar包,如:1582626443_2020_02_25_10.8.2_gitlab_backup.tar 如果修改了配置文件,...

JennerLuo
40分钟前
57
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部