在本文中,我们将为您详细介绍【cocos2dx】运行时内存优化的相关知识,并且为您解答关于cocos2dx内存优化的疑问,此外,我们还会提供一些关于cocos2d-x–Cocos2dX,在构建或运行时
在本文中,我们将为您详细介绍【cocos2dx】运行时内存优化的相关知识,并且为您解答关于cocos2dx 内存优化的疑问,此外,我们还会提供一些关于cocos2d-x – Cocos2dX,在构建或运行时删除资产(Eclipse Juno,Android C项目)、Cocos2d-x教程(19)-cocos2d-x.xcodeproj-2.2.x版本对cocos2dx文件的引用以及Cocos2d-x 2.2.0版本后项目拷贝出来无法运行的原因、cocos2dx内存优化、Cocos2dx引擎笔记——内存优化的有用信息。
本文目录一览:- 【cocos2dx】运行时内存优化(cocos2dx 内存优化)
- cocos2d-x – Cocos2dX,在构建或运行时删除资产(Eclipse Juno,Android C项目)
- Cocos2d-x教程(19)-cocos2d-x.xcodeproj-2.2.x版本对cocos2dx文件的引用以及Cocos2d-x 2.2.0版本后项目拷贝出来无法运行的原因
- cocos2dx内存优化
- Cocos2dx引擎笔记——内存优化
【cocos2dx】运行时内存优化(cocos2dx 内存优化)
针对jpg格式的图片,我使用webp格式进行压缩,但是cocos引擎对图片纹理加载处理比较粗糙,统一按照RGBA8888进行处理的。导致jpg格式文件的内存占用增大了,因为jpg格式是没有alpha通道的,也按照RGBA8888处理就无端增大了内存。我直接加载一个jpg格式纹理,内存占用如下图:
看到这个LoginUI.jpg格式文件占用了2304K的内存,并且bpp为32(bpp为BitsPerPixelForFormat),所以针对这块我做了些优化,分别在同步和异步加载纹理的时候,进行g_defaultAlphaPixelFormat的设置,当加载png格式的时候使用RGBA8888,使用jpg格式的时候使用RGB888。优化后内存占用如下图:
经过优化,该jpg图片内存占用从2304K降低到1728K,降低了25%,效果不错。修改代码如下:
当然,对g_defaultAlphaPixelFormat进行了设置要记得还原。上面是同步加载纹理的时候进行的优化,在异步加载的时候,需要在addImageAsyncCallBack中进行上述优化,因为异步加载的过程是在子线程加载纹理,创建image及回调函数的一个结构体,然后在TextureCache::loadImage把这个结构体塞回到主线程的_asyncStructqueue队列里面,然后再在主线程中进行渲染相关处理,所以需要在回调到主线程之后进行上述优化处理,并且因为是在主线程,所以不用担心线程安全的问题。
cocos2d-x – Cocos2dX,在构建或运行时删除资产(Eclipse Juno,Android C项目)
是否有我需要放置资产的另一个位置.我还需要在项目中的配置文件中手动添加它们(例如:清单文件).
我的系统:
Mac OS Lion
Eclipse Juno
Cocos2D-X v2.1 Beta 3
请指教.
关于资产,您不需要执行任何操作只需运行build_native.sh,Assets文件夹将在proj.android文件夹中由其自己生成.
要知道更多只是打开build_native.sh,因为有三行表示将资源复制到assets文件夹
我希望你得到你的答案祝你好运:如果您有任何疑问,请随时询问.
Cocos2d-x教程(19)-cocos2d-x.xcodeproj-2.2.x版本对cocos2dx文件的引用以及Cocos2d-x 2.2.0版本后项目拷贝出来无法运行的原因
欢迎加入 Cocos2d-x 交流群:193411763
转载时请注明原文地址:http://blog.csdn.net/u012945598/article/details/17954549
今天在使用Cocos2d-x 2.2.1版本中的"curl.h"头文件时遇到了一个问题
提示文件没有找到。
之后笔者对比了一下Cocos2d-x 2.1.5版本,发现在2.1.5的版本中cocos2dx文件(curl文件夹位于cocos2dx文件夹目录下)是以groups(黄色文件夹)的形式存在于项目中的,而在2.2.x版本中采用了新的引入方式,也就是我们所见到的cocos2d-x.xcodeproj
(不理解groups形式请参考http://blog.csdn.net/u012945598/article/details/17955215)
2.1.5版本:
2.2.x版本:
这也就解释了,为什么在2.2.0之后的版本中,如果将你的项目拷贝到了别的电脑上,项目将无法运行的原因。
因为2.2.0之后的版本中,cocos2dx文件夹不再存在于项目的目录下了,而是位于你的系统中的某个位置(下载完之后扔哪了就是哪),当编译器对cocos2dx文件做路径搜索时,会按照创建项目的机器中的cocos2dx文件的路径去搜索,而在另外一台电脑中,路径是不一样的,所以自然会找不到。搜索路径如下图:
我们常用的解决办法就是新建一个项目,将之前项目的Classes文件夹与Resources文件夹拷贝出来,再重新添加到项目中。
从形式上来说,在2.1.5版本中的cocos2dx的文件夹的作用与2.2.x版本中的cocos2dx.xcodeproj的作用是相同的,因为他们都是对cocos2d-x文件夹目录下的cocos2dx文件中的源码的引用。但是在使用过程中,又略有一些区别。
由于在2.1.5的版本中cocos2dx文件是以groups的形式被添加到项目中的,所以在使用的时候,我们可以没有任何顾忌的引用文件中的任何头文件 #include "xxx.h",原因我们在之前的参考文章中已经提过,是因为以groups形式添加到项目中的文件都是会被编译的。
编译的资源文件位置位于Compile Sources如下图:
然而还有一部分文件仍然是以引用的方式存在于项目中,类似于 curl.h,这些文件在使用的过程中并不能直接通过#include "xxx.h"方式获取到它们的头文件,而是要通过其上级目录索引到,例如我们要使用curl文件夹中curl.h的头文件:
#include "curl/curl.h"
又或者我们需要使用到platform中的CCThread类,需要引入头文件
#include "platform/CCThread"
若不加上级目录,就会出现文章开篇中的错误,这就是Cocos2d-x-2.1.5版本与2.2.x版本中cocos2dx中源码使用的区别
cocos2dx内存优化
cocos2dx内存优化 (之二)
本文由qinning199原创,转载请注明:http://www.cocos2dx.net/?p=93
一、内存优化原则
为了优化应用内存,你应该知道是什么消耗了你应用的大部分内存,答案就是Texture(纹理)!它几乎占据了90%的应用内存。那么我们应该尽力去减小我们应用的纹理内存使用,否则我们的应用进程可能会被系统杀死。
为了减少内存警告,这里我们给出两个普遍的关于cocos2dx游戏内存优化的指导原则。
1)了解瓶颈,然后解决掉
什么样的纹理消耗了大部分应用的内存呢?或者说这些纹理消耗了多少内存呢?你不用去手工计算或者猜测。
这里我们正好有一个工具。它就是苹果的开发工具- Allocations & Leaks,在xcode中你长按Run按钮并且选择Profile去启动这两个工具。这里我们有个截图:
你可以使用Allocation工具去计算你应用的内存使用情况并且可以查看内存泄露情况。
你也可以用一些代码去获取游戏内存使用的一些有用的信息。
如下代码即可:
- CCTextureCache::sharedTextureCache()->dumpCachedTextureInfo();
如下所示:当你调用这些代码并且在DEBUG模式运行你的游戏的时候,在你的xcode console窗口你将会看到一些格式化的log信息
- Cocos2d:cocos2d:"cc_fps_images"rc=5id=3256x32@16bpp=>16KB
- Cocos2d:cocos2d:"XXX/hd/actor.pvr.ccz"rc=1059id=42048x2048@32bpp=>16384KB
- Cocos2d:cocos2d:CCTextureCachedumpDebugInfo:2textures,for16400KB(16.02MB)
这些log显示了纹理的名字,引用数,id,大小以及像素的bit值,最重要的是它展示了内存使用情况。如上cc_fps_images消耗了16KB,actor.pvr.ccz消耗了16M内存。
2)不要过度优化
这是一个常规的优化规则。当你进行内存优化的时候,你应当进行一下权衡。因为有时图片质量和图片内存使用情况是相反的两边。所以千万不要过度优化。
二、内存优化等级
这里我们把cocos2dx内存优化划分成三个等级。在每个等级,我们有不同观点并且策略也是有些变化。
1、cocos2dx客户端等级
这是我们可以关心的最重要的优化等级。因为我们在cocos2dx引擎上开发游戏,引擎自己就提供了很多可选择的优化方案。在这个等级上,我们可以做的工作最多。
首先,让我们看一下纹理优化
为了优化纹理内存的使用,我们必须知道什么因素影响了内存的使用情况。
有三个因素影响了纹理的内存使用。纹理格式(压缩的还是非压缩的),颜色,大小。
我们可以使用PVR格式的纹理来减少内存使用。最被建议的纹理格式是pvr.ccz,每色的bit值越高,画面质量就约好。但是也会消费很多内存。
那么我们使用颜色深度是RGBA4444的纹理来代替RBGA8888,这将会消费一半内存。
我们也会发现大纹理也会导致内存相关的问题。那么你最好使用适度的大小。
其次,让我们做一些关于声音的事情
有三个因素影响文件内存使用。是音频文件格式,比特率,和样本率
我们最希望音频文件时mp3格式。因为它被android和ios都支持。并且它也被压缩并且硬件加速了。
你应该保证你的背景音乐文件大小在800KB一下。最简单的方式就是减少背景音乐播放时间并且重复调用。
你应该保持你的音频文件样本率在96-128kbps之间,并且比特率在44kHz就足够了。
最后,我们谈谈字体和粒子系统优化。
这里我们有两个建议:当使用BM字体显示游戏分数,在你的图片文件中选择最小的数字字符,例如:
如果你想只显示数字,你可以移除所有的字符。
粒子系统中,我们可以减少粒子数量来减少内存使用。
2、cocos2dx引擎等级
如果你不擅长OpenGLES和游戏引擎内核,你可以把这部分留个引擎开发者。如果你是一个开源游戏引擎爱好者,如果你已经做了引擎等级的一些优化,请告知引擎开发者们!
3、c++语言等级
在这个等级,我的建议就是写一些无内存泄露的代码。使用cocos2dx引擎内存管理工具并且尽最大努力避免内存泄露。
三、建议和技巧
1、一帧帧的加载游戏资源。
2、减少绘制调用。使用CCSpriteBatchNode
3、按照最大到最小的顺序的加载纹理
4、避开内存使用高峰、
5、使用加载界面来预加载游戏资源。
6、当不需要的时候释放无用的资源
7、当有内存警告的时候释放缓存的资源
8、使用texturePacker来优化纹理尺寸,格式,色彩深度值等等。
9、小心使用JPG文件
10、使用16位RBGA4444色彩深度的纹理
11、使用NPOT纹理代替POT纹理
12、避开加载大尺寸图片
13、使用1024*1024 NPOT pvr.ccz纹理图集而不是原生图片
Cocos2dx引擎笔记——内存优化
内存优化原理
纹理最耗应用内存, 纹理几乎会占据90%应用内存。所以尽量最小化应用的纹理内存使用,否则应用很有可能会因为低内存而崩溃。
认识瓶颈寻找方案
什么样的纹理最耗应用内存?消耗多少内存?利用苹果的工具“Allocation & Leaks”。你可以在Xcode中长按“Run”命令,选择“ Profile ”来启动这两个工具。如下所示:
使用Allocation工具可以监控应用的内存使用,使用Leaks工具可以观察内存的泄漏情况。 此外还可用一些代码获取游戏内存使用的其他信息,如下所示:
CCTextureCache::sharedTextureCache()->dumpCachedTextureInfo();
调用这个代码后,游戏便会在DEBUG模式运行,这时你会在Xcode控制台窗口看到一些格式工整的日志信息。
Cocos2d: cocos2d: "cc_fps_images" rc=5 id=3 256 x 32 @ 16 bpp => 16 KB Cocos2d: cocos2d: "XXX/hd/actor.pvr.ccz" rc=1059 id=4 2048 x 2048 @ 32 bpp => 16384 KB Cocos2d: cocos2d: CCTextureCache dumpDebugInfo: 2 textures,for 16400 KB (16.02 MB)
从上可以看到会显示纹理的名称、引用计数、ID、大小及每像素的位数。最重要的是会显示内存的使用情况。如“cc_fps_images”指消耗了16KB内存,而“actor.pvr.ccz”消耗了16M内存。
切勿过度优化
根据实际需求进行优化,权衡图像质量和图像内存使用。千万不要过度优化!
Ccos2d-x内存优化分为三个等级
一、客户端等级,是最重要的的优化等级。因为我们要在Cocos2d-x引擎顶层编译游戏,引擎自身会提供一些优化选项。 在这个等级我们可以进行大部分优化。简而言之,我们可以优化纹理、音频、字体及粒子的内存使用。
- 1、纹理优化,什么因素对纹理内存使用的影响最大?
- # 纹理格式(压缩还是非压缩)、颜色深度和大小。我们可以使用PVR格式纹理减少内存使用。推荐纹理格式为pvr.ccz。纹理使用的每种颜色位数越多,图像质量越好,但是越耗内存。所以我们可以使用颜色深度为RGB4444的纹理代替RGB8888,这样内存消耗会降低一半。此外超大的纹理也会导致内存相关问题。所以最好使用中等大小的纹理。
- 2、音频优化?
- # 音频文件数据格式、比特率及采样率。推荐使用MP3数据格式的音频文件,因为Android平台和iOS平台均支持MP3格式,此外MP3格式经过压缩和硬件加速。背景音乐文件大小应该低于800KB,最简单的方法就是减少背景音乐时间然后重复播放。音频文件采样率大约在96-128kbps为佳,比特率44kHz就够了。
- 3、字体和粒子优化?在此有两条小提示:使用BMFont字体显示游戏分数时,请尽可能使用最少数量的文字。例如只想要显示单位数的数字,你可以移除所有字母。至于粒子,可以通过减少粒子数来降低内存使用。
二、引擎等级
需要OpenGLES高手,普通人可以略过。
三、C++语言等级
遵循Cocos2d-x内置的内存管理原则,尽量避免内存泄露。
提示和技巧
- 一帧一帧载入游戏资源
- 减少绘制调用,使用“CCSpriteBatchNode”
- 载入纹理时按照从大到小的顺序
- 避免高峰内存使用
- 使用载入屏幕预载入游戏资源
- 需要时释放空闲资源
- 收到内存警告后释放缓存资源.
- 使用纹理打包器优化纹理大小、格式、颜色深度等
- 使用JPG格式要谨慎!
- 请使用RGB4444颜色深度16位纹理
- 请使用NPOT纹理,不要使用POT纹理
- 避免载入超大纹理
- 推荐1024*1024 NPOT pvr.ccz纹理集,而不要采用RAW PNG纹理
推荐阅读
Steffen Itterheim's cocos2d memory optimization tutorialsApple's developer guide for reducing memory usage
引用计数(Reference Count)
引用计数是c/c++项目中一种古老的内存管理方式。参考苹果官方文档NSAutoreleasePool Class Reference。
自动释放池(AutoReleasePool)
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将在消息循环的最后自动释放掉。
使用静态构造函数
Cocos2d-x中所有的类,除了单例,都提供了静态构造函数,这些静态构造函数包含4项操作:
-
新建一个对象
-
调用object->init(…)
-
假如初始化成功,例如,成功的找到纹理文件,那么接下来将会调用object->autorelease()。
- 返回这个已经被标记了autorelease的对象。
所有CCAsdf::createWithXxxx(…)这种类型的函数都有以上这些方式。使用这些静态构造函数,你不需要关心“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()。
纹理缓存(Texture Cache)
纹理缓存是将纹理缓存起来方便之后的绘制工作。每一个缓存的图像的大小,颜色和区域范围都是可以被修改的。这些信息都是存储在内存中的,不用在每一次绘制的时候都发送给GPU。
CCTextureCache
Cocos2d通过调用CCTextureCache或者CCSpriteFrameCache来缓存精灵的纹理。
当这个精灵调用CCTextureCache 或 CCSpriteFrameCache的方法的时候,cocos2dx将使用纹理缓存来创建一个CCSprite。所以你可以预先将纹理加载到缓存中,这样你在场景中使用的时候就非常方便了。怎么样加载这些纹理就看你自己的想法?你可以选择异步加载方式,这样你就可以为loading场景增加一个进度条。
当你创建一个精灵,你一般会使用CCSprite::create(pszFileName)。假如你去看CCSprite::create(pszFileName)的实现方式,你将看到它将这个图片增加到纹理缓存中去了:
bool CCSprite::initWithFile(const char *pszFilename) { CCAssert(pszFilename != NULL,"Invalid filename for sprite"); CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(pszFilename); if (pTexture) { CCRect rect = CCRectZero; rect.size = pTexture->getContentSize(); return initWithTexture(pTexture,rect); } // don't release here. // when load texture Failed,it's better to get a "transparent" sprite than a crashed program // this->release(); returnfalse; }
上面代码显示一个单例在控制加载纹理。一旦这个纹理被加载了,在下一时刻就会返回之前加载的纹理引用,并且减少加载的时候瞬间增加的内存。(详细API请看CCTextureCache API)
CCSpriteFrameCache
CCSpriteFrameCache单例是所有精灵帧的缓存。使用spritesheet和与之相关的xml文件,我们可以加载很多的精灵帧到缓存中,那么之后我们就可以从这个缓存中创建精灵对象了。和这个xml相关的纹理集一般是一个很大的图片,里面包含了很多小的纹理。下面就是一个纹理集的例子:
加载纹理集到CCSpriteFrameCache的三种方式:
- 加载一个xml(plist)文件
- 加载一个xml(plist)文件和一个纹理集
- 通过CCSpriteFrame和一个精灵帧的名字
具体完整API请看CCSpriteFrameCache API。
样例:
CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache(); cache->addSpriteFramesWithFile(“family.plist”,“family.png”);
使用缓存的原因就是减少内存,因为当你使用一个图片创建一个精灵的时候,如果这个图片不在缓存中,那么就会将他加载到缓存中,当你需要用相同的图片来新建精灵的时候,就可以直接从缓存中取得,而不用再去新分配一份内存空间。
CCSpriteFrameCache vs. CCSpriteBatchNode
- 最好是尽可能的使用spritesheets (CCSpriteBatchNodes)。这样的方式是减少draw的调用次数。Draw的调用是非常耗时的。每一个batchnode调用一次draw就可以绘制上面所有的节点,而不是每一个节点的draw都单独调用一次,
- CCSpriteBatchNode渲染所有的子节点只需要一次,只需要调用一次draw。那就是为什么你需要把精灵加载batch node的原因,因为可以统一一起渲染。但是只有这个精灵使用的纹理包含在batch node中的才可以添加到batch node上,因为batch node一次只渲染这相同的纹理集。
- 假如你把精灵添加到其他的节点上。那么每一个精灵就会调用自己的draw函数,batch node就没起作用了。
- CCSpriteBatchNode也是一个常用节点。你可以从场景中像其他节点一样移除掉。纹理集和精灵帧都被缓存在CCTextureCache 和 CCSpriteFrameCache单例中。假如你想要从内存中移除纹理集和精灵帧,那么你不得不通过缓存类来完成这个工作。
各平台硬件所允许的最大纹理尺寸
纹理大小由于硬件和操作系统原因是有限制的。这里我们提供一个不同平台模拟器上纹理大小限制的表格
iPhone3 iPhone3gs iPhone4platform | maxsize in pixels |
---|---|
win32 | 2048*2048 |
Android | 4096*4096 |
1024*1024 | |
2048*2048 | |
2048*2048 |
在真实的机器上面,也有一些不同的限制,这里有一些测试结果:G31024*1024,iPhone4 2048*2048
因此对于开发者来说,假如你想要跨平台,并且游戏运行流畅,你最好保持你的纹理大小小于1024*1024,这个是大多数机器的限制。
声明:本文是对http://www.cocos.com/帮助文档,的阅读笔记
我们今天的关于【cocos2dx】运行时内存优化和cocos2dx 内存优化的分享就到这里,谢谢您的阅读,如果想了解更多关于cocos2d-x – Cocos2dX,在构建或运行时删除资产(Eclipse Juno,Android C项目)、Cocos2d-x教程(19)-cocos2d-x.xcodeproj-2.2.x版本对cocos2dx文件的引用以及Cocos2d-x 2.2.0版本后项目拷贝出来无法运行的原因、cocos2dx内存优化、Cocos2dx引擎笔记——内存优化的相关信息,可以在本站进行搜索。
本文标签: