Cocos2d-x学习笔记四—— 内存管理

内存管理:

  • C/C++内存管理机制
  • 引用计数机制
  • 自动释放池
  • 纹理缓存

在对Cocos2d的内存管理机制进行认识之前,我们先回忆一下之前C/C++里面的内存管理机制new / delete,malloc / free,帮助我们更好的认识Cocos2d的内存管理。

C/C++内存管理机制

在C中,我们如果要为对象,变量分配内存,我们会使用malloc,对应释放用free;在C++中,我们会new一个对象来分配内存,用delete来做释放。

我们在普通项目中新建两个文件GameObject.h以及GameObject.cpp,如图:

GameObject.h:

#ifndef __GAMEOBJECT_H__
#define __GAMEOBJECT_H__

class GameObject
{
public:
	int count;
	GameObject();
	~GameObject();
private:
};

#endif // !__GAMEOBJECT_H__
GameObject.cpp:
#include "GameObject.h"

GameObject::GameObject() 
{
	count = 1;
}

GameObject::~GameObject()
{
}
main.cpp:
int main()
{
	// c++中内存管理的方法,这里会调用构造函数和析构函数
	GameObject *gameobject = new GameObject();
	gameobject->count = 0;
	delete gameobject;

	GameObject *gameobject2 = new GameObject[4];
	gameobject2->count = 0;
	delete[] gameobject2;


	// c中内存管理的方法,需要强制类型转换,c 中不会调用构造函数,因为c没有类
	GameObject *gameobject3 = (GameObject*)malloc(sizeof(GameObject));
	gameobject3->count = 0;
	free(gameobject3);
}

引用计数机制

引用计数的关键作用在于,当我们创建一个对象后,该对象被其他对象引用,为防止在释放的时候出现错误,我们使用引用计数表明被引用的次数,因而需要所有引用对象及对象本身被释放,此对象才能算是被完全释放。修改上面的HelloWorld项目。

GameObject.h:

<pre name="code" class="cpp">#ifndef __GAMEOBJECT_H__
#define __GAMEOBJECT_H__

class GameObject
{
public:
     int age;
     int count;
     GameObject();
     ~GameObject();
     void freeobject();
private:
};

#endif // !__GAMEOBJECT_H__
 
GameObject.cpp: 
#include "GameObject.h"

GameObject::GameObject()
{
	count = 1;
}

GameObject::~GameObject()
{
	freeobject();
}

void GameObject::freeobject()
{
	--count;
	if (count <= 0)
	{
		delete this;
	}
}
main.cpp:
#include <iostream>
using namespace std;

int main()
{
	// 引用计数机制
	GameObject *gameobject = new GameObject();
	// 创建一次对象,引用计数count加 1
	GameObject *gameobject2 = gameobject;
	// 这里引用计数的作用在于防止gameobject被释放后,gameobject2的内存为空,导致使用时出错
	gameobject->count++;
	cout << count << gameobject->count << endl;
	// 调用函数释放对象,释放时引用计数减 1,直到引用计数为 0时释放对象
	gameobject->freeobject();
	cout << count << gameobject->count << endl;
	// 这里能调用age说明对象还没有被释放,只是引用计数减 1
	gameobject2->age = 2;
	gameobject2->freeobject();
	cout << count << gameobject->count << endl;
	// gameobject->count = 0;	// 这里引用计数已经为0,对象被释放,因此调用时会出错
}

输出结果:

count:2
count:1
count:-17891602


Cocos2d的引用计数函数:

sprite->retain()		// 引用计数加1
sprite->release()		// 释放对象,引用计数减1
sprite->getReferenceCount()	// 获取引用计数
节点数引用计数函数:
	virtual void addChild(CCNode *child);
	virtual void addChild(CCNode *child,int zOrder);
	virtual void addChild(CCNode *child,int zOrder,int tag);
	virtual void removeChild(CCNode *child,bool cleanup);
	void removeChildByTag(int tag,bool cleanup);
	virtual void removeAllChildrenWithCleanup(bool cleanup);

新建一个Cocos2d项目“HelloWorld”,在HelloWorldScene.cpp中的bool HelloWorld::init()函数中添加以下代码:

	CCSprite *sprite = new CCSprite();
	log("spritecount:%d",sprite->getReferenceCount());<span style="white-space:pre">	</span>// 获取引用计数
	CCSprite *sprite2 = sprite;
	sprite2->retain();<span style="white-space:pre">	</span>// 引用计数加1操作
	log("spritecount:%d",sprite->getReferenceCount());
	// 这里被添加到图层,引用计数也会加1
	this->addChild(sprite);
	log("spritecount:%d",sprite->getReferenceCount());
	this->removeChild(sprite);
	log("spritecount:%d",sprite->getReferenceCount());
	sprite2->release();<span style="white-space:pre">	</span>// 释放对象,引用计数减 1
	log("spritecount:%d",sprite->getReferenceCount());
	sprite->release();
	log("spritecount:%d",sprite->getReferenceCount());

运行结果:

spritecount:1
spritecount:2
spritecount:3
spritecount:2
spritecount:1
spritecount:-17891602


自动释放池(CCAutoreleasePool)

CCAutoreleasePool不能被开发者自己创建。Cocos2d-x会为我们每一个游戏创建一个自动释放池实例对象,游戏开发者不能新建自动释放池,仅仅需要专注于release/retain cocos2d::CCObject的对象。

静态构造函数包含autorelease()函数,调用这样的函数不需要手动释放,自动释放池会帮我们做释放,这样的静态函数有:

CCAsdf::createWithXxxx(…)
object->init(…)

代码实例:
<pre name="code" class="cpp">CCSprite *sprite = CCSprite::create("HelloWorld.png");
this->addChild(sprite);
等同于
        CCSprite *sprite = new CCSprite();
	sprite->initWithFile("HelloWorld.png");
	sprite->autorelease();<span style="white-space:pre">		</span>// 对象会在结束时被自动释放
	this->addChild(sprite);


纹理缓存(TextureCache)

CCTextureCache继承自TextureCache,纹理(纹理可看做像素)缓存是将纹理缓存起来方便之后的绘制工作。每一个缓存的图像的大小,颜色和区域范围都是可以被修改的。这些信息都是存储在内存中的,不用在每一次绘制的时候都发送给GPU。下次可直接利用缓存,避免重新绘制,减少CPU和GPU内存的消耗。

下面为Cocos2d中的源代码,会把添加的图片加入到纹理缓存,这些在Cocos2d底层实现,我们可以直接调用:

<pre name="code" class="cpp">bool Sprite::initWithFile(const std::string& filename)
{
    CCASSERT(filename.size()>0,"Invalid filename for sprite");
    // 由导演获取纹理缓存,缓存图片,下次需要图片时可直接从texture获取
    Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);
    if (texture)
    {
        Rect rect = Rect::ZERO;
        rect.size = texture->getContentSize();
        return initWithTexture(texture,rect);
    }

    // don't release here.
    // when load texture failed,it's better to get a "transparent" sprite then a crashed program
    // this->release();
    return false;
}
 


V3.0新特性(官方发表内容):

Sprite 和 SpriteBatchNode

v2.2 2.2版本中推荐的优化游戏方式是将SpriteBatchNode对象设置为Sprite对象的父节点。 虽然使用SpriteBatchNode对象仍然是一个非常好的优化游戏的方式,但是它仍然有一定的限制:

  • Sprite对象的孩子只能是Sprite(否则,Cocos2d-x 会触发断言)
    • Sprite的父节点是SpriteBactchNode时,不能添加ParticleSystem作为Sprite的子节点。
    • 这将导致当SpriteBatchNode时,不能使用ParallaxNode
  • 所有的Sprite对象必须共享相同的纹理ID (否则,Cocos2d-x 会触发断言)
  • Sprite对象使用SpriteBatchNode的混合函数和着色器。

虽然 v3.0 仍然支持SpriteBatchNode(与之前的版本拥有相同的特效和限制),但是我们不鼓励使用它。相反,我们推荐直接使用Sprite,不需要再它作为子节点添加到SpriteBatchNode中。

但是,为了能让 v3.0 有更好的表现,你必须要确保你的Sprite对象满足以下条件:

  • 贡献相同的纹理ID(把它们放在一个spritesheet中,就像使用SpriteBatchNode一样)
  • 确保它们使用相同的着色器和混合函数(就像使用SpriteBatchNode一样)

如果这么做,Sprites将会像使用SpriteBatchNode一样的快...(在旧设备上大概慢了10%,在新设备上基本上察觉不出)

v2.2 和 v3.0 最大的区别在于:

    Sprite对象可以有不同的纹理ID。
  • Sprite对象可以有不同种类的Node作为子节点,包括ParticleSystem
  • Sprite对象可以有不同的混合函数和不同的着色器。

但是如果你这么做,渲染器可能无法对它所有的子节点进行批处理(性能较低)。但是游戏仍然可以正常运行,不会触发任何断言。

总结:

  • 保持将所有的精灵放在一张大的 spritesheet 中。
  • 使用相同的混合函数(使用默认)
  • 使用相同的着色器(使用默认)
  • 不要将精灵添加到SpriteBatchNode

只有当你需要一些额外的性能上提升(虽然很小),SpriteBatchNode才会是你最后的选择(你需要对它的限制条件很熟悉)。

提示和技巧(摘自官方文档)

  1. 一帧一帧载入游戏资源
  2. 载入纹理时按照从大到小的顺序
  3. 避免高峰内存使用
  4. 使用载入屏幕预载入游戏资源
  5. 需要时释放空闲资源
  6. 收到内存警告后释放缓存资源.
  7. 使用纹理打包器优化纹理大小、格式、颜色深度等
  8. 使用JPG格式要谨慎!
  9. 请使用RGB4444颜色深度16位纹理
  10. 请使用NPOT纹理,不要使用POT纹理
  11. 避免载入超大纹理
  12. 推荐1024*1024 NPOT pvr.ccz纹理集,而不要采用RAW PNG纹理

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


    本文实践自 RayWenderlich、Ali Hafizji 的文章《How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.4进行学习和移植。在这篇文章,将会学习到如何创建实时纹理、如何用Gimp创建无缝拼接纹
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@163.com微信公众号:HopToad 欢迎转载,转载标注出处:http://blog.csdn.netotbaron/article/details/424343991.  软件准备 下载地址:http://cn.cocos2d-x.org/download 2.  简介2.1         引用C
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从Cocos2D-x官网上下载,进入网页http://www.cocos2d-x.org/download,点击Cocos2d-x以下的Download  v3.0,保存到自定义的文件夹2:从python官网上下载。进入网页https://www.python.org/downloads/,我当前下载的是3.4.0(当前最新
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发引擎,易学易用,支持多种智能移动平台。官网地址:http://cocos2d-x.org/当前版本:2.0    有很多的学习资料,在这里我只做为自己的笔记记录下来,错误之处还请指出。在VisualStudio2008平台的编译:1.下载当前稳
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《最强大脑》娱乐节目。将2048改造成一款挑战玩家对数字记忆的小游戏。邮箱:appdevzw@163.com微信公众号:HopToadAPK下载地址:http://download.csdn.net/detailotbaron/8446223源码下载地址:http://download.csdn.net/
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试以QtCreatorIDE来进行CMake构建。Cocos2d-x3.X地址:https://github.com/cocos2d/cocos2d-x1.打开QtCreator,菜单栏→"打开文件或项目...",打开cocos2d-x目录下的CMakeLists.txt文件;2.弹出CMake向导,如下图所示:设置
 下载地址:链接:https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ提取码:p1pb下载完成后,解压进入build目录使用vs2013打开工程设置平台工具集,打开设置界面设置: 点击开始编译等待编译结束编译成功在build文件下会出现一个新文件夹Debug.win32,里面就是编译
分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net前言上次用象棋演示了cocos2dx的基本用法,但是对cocos2dx并没有作深入的讨论,这次以超级马里奥的源代码为线索,我们一起来学习超级马里奥的实
1. 圆形音量button事实上作者的本意应该是叫做“电位计button”。可是我觉得它和我们的圆形音量button非常像,所以就这么叫它吧~先看效果:好了,不多解释,本篇到此为止。(旁白: 噗。就这样结束了?)啊才怪~我们来看看代码:[cpp] viewplaincopyprint?CCContro
原文链接:http://www.cnblogs.com/physwf/archive/2013/04/26/3043912.html为了进一步深入学习贯彻Cocos2d,我们将自己写一个场景类,但我们不会走的太远,凡是都要循序渐进,哪怕只前进一点点,那也至少是前进了,总比贪多嚼不烂一头雾水的好。在上一节中我们建
2019独角兽企业重金招聘Python工程师标准>>>cocos2d2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图
原文链接:http://www.cnblogs.com/linji/p/3599478.html1.环境和工具准备Win7VS2010/2012,至于2008v2版本之后似乎就不支持了。 2.安装pythonv.2.0版本之前是用vs模板创建工程的,到vs2.2之后就改用python创建了。到python官网下载版本2.7.5的,然后
环境:ubuntu14.04adt-bundle-linux-x86_64android-ndk-r9d-linux-x86_64cocos2d-x-3.0正式版apache-ant1.9.3python2.7(ubuntu自带)加入环境变量exportANDROID_SDK_ROOT=/home/yangming/adt-bundle-linux/sdkexportPATH=${PATH}:/$ANDROID_SDK_ROOTools/export
1开发背景游戏程序设计涉及了学科中的各个方面,鉴于目的在于学习与进步,本游戏《FlappyBird》采用了两个不同的开发方式来开发本款游戏,一类直接采用win32底层API来实现,另一类采用当前火热的cocos2d-x游戏引擎来开发本游戏。2需求分析2.1数据分析本项目要开发的是一款游
原文链接:http://www.cnblogs.com/linji/p/3599912.html//纯色色块控件(锚点默认左下角)CCLayerColor*ccc=CCLayerColor::create(ccc4(255,0,0,128),200,100);//渐变色块控件CCLayerGradient*ccc=CCLayerGradient::create(ccc4(255,0,0,
原文链接:http://www.cnblogs.com/linji/p/3599488.html//载入一张图片CCSprite*leftDoor=CCSprite::create("loading/door.png");leftDoor->setAnchorPoint(ccp(1,0.5));//设置锚点为右边中心点leftDoor->setPosition(ccp(240,160));/
为了答谢广大学员对智捷课堂以及关老师的支持,现购买51CTO学院关老师的Cocos2d-x课程之一可以送智捷课堂编写图书一本(专题可以送3本)。一、Cocos2d-x课程列表:1、Cocos2d-x入门与提高视频教程__Part22、Cocos2d-x数据持久化与网络通信__Part33、Cocos2d-x架构设计与性能优化内存优
Spawn让多个action同时执行。Spawn有多种不同的create方法,最终都调用了createWithTwoActions(FiniteTimeAction*action1,FiniteTimeAction*action2)方法。createWithTwoActions调用initWithTwoActions方法:对两个action变量初始化:_one=action1;_two=action2;如果两个a
需要环境:php,luajit.昨天在cygwin上安装php和luajit环境,这真特么是一个坑。建议不要用虚拟环境安装打包环境,否则可能会出现各种莫名问题。折腾了一下午,最终将环境转向linux。其中,luajit的安装脚本已经在quick-cocos2d-x-develop/bin/中,直接luajit_install.sh即可。我的lin
v3.0相对v2.2来说,最引人注意的。应该是对触摸层级的优化。和lambda回调函数的引入(嗯嗯,不枉我改了那么多类名。话说,每次cocos2dx大更新。总要改掉一堆类名函数名)。这些特性应该有不少人研究了,所以今天说点跟图片有关的东西。v3.0在载入图片方面也有了非常大改变,仅仅只是