【问题标题】:How to find out what eats up memory in Cocos2d如何在 Cocos2d 中找出占用内存的内容
【发布时间】:2012-06-08 14:16:30
【问题描述】:

我正在使用 Cocos2D for iOS 开发游戏。

有一些像菜单之类的场景和一个主要的游戏场景。在主场景中只有三个动态对象。这些对象周期性地互相射击(直到这些对象被杀死或移出场景)。

现在的问题是:游戏不断消耗内存。我想找出我做错了什么。

没有像过度保留的对象这样的明显泄漏。场景获取dealloced,对象从父对象中移除并清理,动画停止等。

无论如何,记忆总是在某个地方。我正在使用以下代码

+ (void) reportMemory
{
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(),
                                   TASK_BASIC_INFO,
                                   (task_info_t)&info,
                                   &size);
    if (kerr == KERN_SUCCESS)
        NSLog(@"Memory in use (in Kbytes): %f", info.resident_size / 1024.0);
    else
        NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
}

找出每个场景开始时消耗了多少内存。并且报告的数字总是大于前一个。

我尝试使用分配分析器,但老实说,我无法找出任何有用的东西。我看到总生存字节基本相同,但进程不断分配和释放一些东西。

你建议我看什么?基本上,我正在寻求有关如何在我的情况下调试内存操作的建议。

编辑(对我有什么帮助):

原来我打开了 NSZombieEnabled。基本上,这是内存消耗不断增加的主要因素。可以在@coneybeare answer中找到一些有用的信息和提示

第二个最有用的事情是使用 @Jack 建议的工具(泄漏和分配)。它帮助我发现了几个微妙的漏洞。

【问题讨论】:

  • 你的总生存字节数是多少?
  • @meccan 起初它大约是 42 Mb(此时预缓存了精灵图集的数量),然后每次运行场景时它会增长大约 2-5 Mb,一直到大约125 MB。在该进程被操作系统杀死之后。
  • 哦,太疯狂了。你用过缓存的图片吗?
  • @meccan 是的,我预缓存了八个纹理图集(32bpp PNG)
  • 只是一个猜测,但也许您的缓存不正确,并为每一帧分配新纹理。

标签: ios memory-leaks cocos2d-iphone profiling xcode4.2


【解决方案1】:

仪器绝对是你的朋友,是什么东西吃掉了你的记忆然后你就能看到它。

您应该使用的第一件事是 leaks 工具(不是 allocation 工具),它将通过每 X 秒采样一次内存来显示泄漏。

如果您单击特定的已识别泄漏,您可以看到

  • A 发现泄漏的负责调用链中
  • 通过单击B中的小箭头,您可以看到内存泄漏的确切生活进程(例如它被malloc'd、保留、释放等等)

如果这还不够,通过选择 allocations 工具,您会在左侧有一个标有 Mark Heap 的按钮。每次单击此按钮都会创建堆的快照,并且它能够向您显示确切的差异,以便您能够查看在不应该有的两个时刻之间是否有分配的内存和从未释放的内存.

有了这些,我总能找到任何与内存相关的问题!

【讨论】:

  • +1 当您可以花同样多的时间学习更强大的调试工具时,不要编写自己的调试工具!
  • @Jack 谢谢。我会再次尝试使用分配。
【解决方案2】:

我将首先查看纹理缓存,如下所示:

[[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];

在每个场景开始时执行此操作。纹理可以是真正的内存猪。可能您以某种方式保留了一些纹理(一种快速的方法是通过也在某处缓存中的 spriteFrames),或者保留的引用可能在您的数据模型中的某个地方。这是我的#if DEBUG memoryWarning 委托:

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    CCLOG(@"AppDelegate<applicationDidReceiveMemoryWarning> : before purging all caches");
    [[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];
    [[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
    [[CCDirector sharedDirector] purgeCachedData];
    CCLOG(@"AppDelegate<applicationDidReceiveMemoryWarning> : after purging all caches");
    [[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];
}

【讨论】:

  • 我尝试了几乎相同的方法。输出是预期的(我没有看到任何问题)。
  • +1。不要依赖 applicationDidReceiveMemoryWarning 来拯救你,因为有时应用程序没有时间调用它。最好边走边清理。在旧设备上的一些密集场景中,我每隔几秒钟在计时器上运行一次这些清除。
  • @DanyalAytekin :完全是项目的“问题发现”阶段。类似的 sn-ps 代码现在也出现在整个应用程序中,尤其是在转换附近,特别注意让运行循环有机会清除自动释放对象。
【解决方案3】:

确保你没有在 Cocos 层次结构中保留任何对象;除非 Cocos 拥有它们的唯一控制权和所有权,否则 Cocos 内置的清理对象的方法并不总是有效;如果您将 Sprites 或 Layers 存储为保留的 iVar,将它们的引用计数增加到超出正常 Cocos 所有权的范围,那么它们可能无法按预期清理。出于这个原因,在保存指向 Cocos 对象的指针时,我总是使用 assign 属性。

【讨论】:

  • 谢谢。我能读到关于这个问题的任何东西(书籍或文章)吗?我在几个地方保留了动画,现在想知道如果不保留,我应该如何做同样的事情。
  • Steffen Iterheim 的书(拼写?)和 Steffen 本人在 SO 上对 Cocos2D 的内存问题有很多话要说
猜你喜欢
  • 2012-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-07
  • 1970-01-01
  • 2011-09-23
相关资源
最近更新 更多