Cocos2d-x学习笔记(四)—— 内存管理
|
内存管理:
在对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
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
自动释放池(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版本中推荐的优化游戏方式是将
虽然 v3.0 仍然支持 但是,为了能让 v3.0 有更好的表现,你必须要确保你的
如果这么做, v2.2 和 v3.0 最大的区别在于:
但是如果你这么做, 总结:
只有当你需要一些额外的性能上提升(虽然很小), 提示和技巧(摘自官方文档)
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
