Cocos2d-x与iOS内存管理分析

2015年03月22日 17:13 0 点赞 0 评论 更新于 2025-11-21 18:12

一、iOS与图片内存

在iOS系统中,图片会自动缩放到2的N次方大小。例如,一张尺寸为1024 1025的图片,其占用的内存与一张1024 2048的图片相同。图片占用内存大小的计算公式为:长 4。以一张512 512的图片为例,其占用的内存为512 512 4 = 1MB,其他尺寸的图片可依此公式计算。需要注意的是,iOS上支持的图片最大尺寸为2048 2048。

二、Cocos2d - x的图片缓存

在Cocos2d - x中,当构造一个精灵时,通常会使用spriteWithFile或者spriteWithSpriteFrameName等方法。无论采用哪种方式,Cocos2d - x都会将图片加载到缓存中。若为首次加载该图片,会先将其加载到缓存,再从缓存中读取;若缓存中已存在该图片,则直接从缓存提取,避免了重复加载过程。

图片的缓存主要由以下两个类负责处理:

  • CCSpriteFrameCache:该类用于加载拼接过的大图,其中每个小图只是大图中的一个区域,这些区域信息存储在plist文件中。使用时,只需根据小图的名称即可加载对应的区域。
  • CCTextureCache:这是普通的图片缓存,所有直接加载的图片默认都会存放在此缓存中,以提高调用效率。

因此,每次加载一张图片,或者通过plist加载一张拼接图时,都会将整张图片加载到内存中。若不进行释放操作,图片将一直占用内存。

三、渲染内存

在计算内存时,不能仅仅考虑加载到缓存中的内存。下面通过具体示例进行说明:

直接加载图片

以一张1024 * 1024的图片为例,执行以下代码:

CCSprite *pSprite = CCSprite::spriteWithFile("a.png");

调用上述代码后,通过LEAKS工具可以观察到,内存大约增加了4MB。接着执行:

addChild(pSprite);

此时,内存又增加了4MB。这表明,如果一张图片需要进行渲染,其占用的内存会变为原来的2倍。

通过plist加载图片

假设一张大图尺寸为2048 2048,要加载其中一张32 32的小图片,执行以下代码:

CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("b.plist");

此时,内存会增加16MB。继续执行:

CCSprite *pSpriteFrame = CCSprite::spriteWithSpriteFrameName("b1.png");

尽管b.png大小仅为32 * 32,但实际内存增加了16MB。这意味着只要渲染了图片的一部分,整张图片都会被加载到内存中。

不过,已经渲染过的图片,再次加载时内存不会继续升高。例如,再增加100个b.plist的另一个区域,图片内存总共增加16 + 16 = 32MB,不会持续上升。

四、缓存释放

如果游戏包含多个场景,在场景切换时可以释放前一个场景的内存,防止总内存过高。以下是一些常见的释放方法:

CCTextureCache::sharedTextureCache()->removeAllTextures();

该方法用于释放到目前为止所有加载的图片。

CCTextureCache::sharedTextureCache()->removeUnusedTextures();

此方法会将引用计数为1的图片释放掉。此外,还可以使用CCTextureCache::sharedTextureCache()->removeTexture()单独释放某个图片。CCSpriteFrameCache与CCTextureCache的释放方法类似。

需要注意释放的时机,一般在切换场景时释放资源。如果从A场景切换到B场景,正常情况下函数的调用顺序为B::init() —-> A::exit() —-> B::onEnter()。但如果使用了切换效果,如CTransitionJumpZoom::transitionWithDuration这样的函数,函数的调用顺序会变为B::init() —-> B::onEnter() —-> A::exit()。而且第二种方式会有一瞬间将两个场景的资源叠加在一起,如果不采取过渡措施,很可能因内存吃紧而导致程序崩溃。

有时强制释放全部资源时,可能会使某个正在执行的动画失去引用而抛出异常,可调用CCActionManager::sharedManager()->removeAllActions()来解决。

五、内存优化

内存优化的关键在于尽量拼接图片,使图片边长尽可能保持为2的N次方,并且充分利用图片空间。同时,有逻辑关系的图片应尽量打包在一张大图里,打包时还需考虑层的分布。因为为了提高渲染效率,可能会使用CCSpriteBatchNode,同一个BatchNode里的图片必须位于同一层级,所以要根据各个图片的层级关系,将其打包到不同的plist文件中。在实际操作中,内存和效率往往难以兼顾,只能尽量寻求平衡。

六、其他

最后附上各代iOS设备的内存限制情况: | 设备 | 建议内存 | 最大内存 | | ---- | ---- | ---- | | iPad2/iPhone4s/iPhone4 | 170 - 180MB | 512MB | | iPad/iPod touch3,4/iPhone3gs | 40 - 80MB | 256MB | | iPod touch1,2/iPhone3g/iPhone1 | 25MB | 128MB |

上述建议内存是部分开发者测试的结果,设备可用的RAM一般不大于最大内存的一半,若程序占用内存超过最大内存的一半,可能会导致程序崩溃。另外,在LEAKS工具中查看模拟器和真机的总内存时,会存在较大差异,模拟器中的结果与实际情况更为接近。

作者信息

menghao

menghao

共发布了 3994 篇文章