2

I am developing a game using Cocos2D for iOS.

There are some scenes like menu and the like and a main game scene. On the main scene there is only three dynamic objects. These objects periodically shoot at each other (until these objects are killed or moved out of the scene).

Now the problem: the game constantly eats up memory. And I want to find out what I am doing wrong.

There are no obvious leaks like over-retained objects. Scene gets dealloced, objects gets removed from parents and cleaned up, animations gets stopped etc.

Anyway, the memory keeps going somewhere. I am using following code

+ (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));
}

to find how much memory consumed at each start of the scene. And reported number is always greater then previous one.

I tried to use allocations profiler but honestly I wasn't able to figure out anything useful. I see that total living bytes are basically the same, but process constantly allocates and deallocates something.

What would you suggest me to look at? Basically, I am seeking advices for how to debug memory operations in my case.

EDIT (What have helped me):

It turned out that I had NSZombieEnabled turned on. Basically, it was the main factor for constant memory consumption increases. Some useful information and a tip can be found in a @coneybeare answer

The second most useful thing was to use Instruments (Leaks and Allocations) as @Jack suggested. It helped me to find couple of subtle leaks.

Community
  • 1
  • 1
Bobrovsky
  • 13,789
  • 19
  • 80
  • 130

3 Answers3

5

Instruments is absolutely your friend, is something eats up memory then you are able to see it.

First thing you should use is the leaks instrument (which is not the allocation one) that will show leaks by sampling memory every X seconds.

If you click a specific recognised leak you can see

  • in A the responsible call chain where the leak is found
  • by clicking the small arrow in B you can see the exact living progression of the memory leaked (like when it has been malloc'd, retained, released and whatever)

Leaks Xcode

If this is not enough, by choosing the allocations instruments, you have a button on the left labeled Mark Heap. This button creates a snapshot of the heap everytime is clicked and it is able to show you the exact differences, so that you are able to see if there is memory which is allocated and never released between two moments in which there shouldn't be any.

enter image description here

With these I've always been able to find any memory related issue!

Jack
  • 131,802
  • 30
  • 241
  • 343
3

I would start by looking at the texture cache as follows :

[[CCTextureCache sharedTextureCache] dumpCachedTextureInfo];

do that at the start of each scene. Textures can be real memory hogs. Possibly you are somehow holding on to some textures (a quick way to do that is via spriteFrames that are also in a cache somewhere), or the retained references could be in your data model somewhere. Here is my #if DEBUG memoryWarning delegate :

- (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];
}
YvesLeBorg
  • 9,070
  • 8
  • 35
  • 48
  • I tried almost the same. The output is kind of expected (I didn't see any issues). – Bobrovsky Jun 04 '12 at 16:04
  • 1
    +1. Don't rely on applicationDidReceiveMemoryWarning to save you though, as sometimes the app doesn't have time to call it. Better to clean up as you go. In some intensive scenes on older devices I run these purges on a timer every couple of seconds. – Danyal Aytekin Jun 05 '12 at 12:24
  • @DanyalAytekin : totally, that was the 'problem discovery' phase of the project. Similar snippets of code now also appear here and there throughout the app, especially near transitions, with special attention given to giving the run loop a chance to clean out autorelease objects. – YvesLeBorg Jun 05 '12 at 20:11
2

Make sure you are not retaining any objects within the Cocos heirarchy; Cocos built in methods for cleaning up objects don't always work unless Cocos has sole control and ownership of them; if you store Sprites or Layers as retained iVars, increasing their reference count beyond the normal Cocos ownership, then they may not get cleaned up as expected. I always use assign properties when keeping pointers to Cocos objects for this reason.

johnbakers
  • 24,158
  • 24
  • 130
  • 258
  • Thank you. Is there anything I can read about this issue (books or articles)? I am retaining animations in couple of places and now wonder how should I do the same without retaining. – Bobrovsky Jun 04 '12 at 16:11
  • 1
    Steffen Iterheim's book (spelling?) and Steffen himself here on SO have a lot to say about memory issues with Cocos2D – johnbakers Jun 04 '12 at 17:04