Memory Leak using stringWithFormat

Member
Posts: 65
Joined: 2009.03
Post: #1
I've got what is maybe a simple question but one which I've not worked out.

I am creating some strings within the render part of my game loop to display info on screen using my bitmap font class. To do this I'm using:

Code:
string = [NSString stringWithFormat:@"Test %d", num]

When running this through Instruments I can see that memory usage is getting higher and higher. If I remove that line of code from the render method memory is stable with no leaks and it does not get higher. Put it back in and memory usage just keeps getting higher as the game runs although no leaks are reported.

I thought that using stringWithFormat would handle memory management itself so I'm not sure why memory is not being released and keeps rising Huh

Does anyone have any ideas?

Thanks

MikeD
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #2
Do you have an autorelease pool in place, and is it getting drained between game loop iterations? When you say "my game loop", it implies to me that you're never returning to Cocoa's main run loop, which means you'll have to manage your own autorelease pool inside your loop if you want memory to be released for things like this.
Quote this message in a reply
Member
Posts: 65
Joined: 2009.03
Post: #3
Thanks for the reply ThemsAllTook

I do have a tight game loop which does not use the NSTimer. The loop code is something I picked up from another post on this forum and I've posted it below.

Code:
- (void)mainGameLoop {
    
    //Get the resolution of the iPhone timer.
    mach_timebase_info_data_t timerInfo;
    mach_timebase_info(&timerInfo);
    
    //Store the ratio between the numberator and the denominator.
    const float TIMER_RATIO = ((float)timerInfo.numer / (float)timerInfo.denom);
    
    //The resolution of the iPhone is in nanoseconds.
    const uint64_t RESOLUTION = 1000000000;
    
    //Create a target time variable based upon the iPhone timer resolution and our FPS.
    const float TARGET_TIME = (float)RESOLUTION / 60;
    
    //Start the frame average at the target time for a frame.
    float frameAverage = TARGET_TIME;
    
    //Create an artificial last update time that matches our target delta.
    double lastUpdateTime = mach_absolute_time() * TIMER_RATIO - TARGET_TIME;
    
    //It will act this many times before it draws.
    const unsigned int DRAW_FREQUENCY = 0;
    unsigned int timesUpdated = 0;
    
    //Start the game loop.
    while (true)
    {
        //Get the current time and convert it to a useable standard value (ns).
        uint64_t now = mach_absolute_time() * TIMER_RATIO;
        
        //Adjust the frame average based upon how long this last update took us.
        frameAverage = (frameAverage * 10 + (now - lastUpdateTime)) / 11;
        
        //Create a delta out of the value for the current frame average.
        float delta = frameAverage / TARGET_TIME;
        
        //Refresh the last update time.
        lastUpdateTime = now;
        
        //Yield to system calls (touches, etc.) for one ms.
        while( CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, FALSE) == kCFRunLoopRunHandledSource);
        
        //Update the game logic.
        [self updateScene:delta];
        
        //Draw the game.
        timesUpdated++;
        if (timesUpdated >= DRAW_FREQUENCY)
        {
            [self renderScene];
            timesUpdated = 0;
        }
    }    
}

I do have an autorelease pool being configured in main which is the pool that is included in the project as standard (my project started out as the OpenGL ES project). Within the game loop above I am handling CFRunLoopRuInMode which I had assumed should be draining the autorelease pool for me.

Any ideas what else it could be?

Cheers

MikeD
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #4
I'm fairly certain CFRunLoopRunInMode won't drain an existing autorelease pool and set up a new one for you, though I wouldn't be surprised if it sets up its own for the duration of your call to it. However, this won't help with anything in your -updateScene: or -renderScene methods. Try putting NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; as the first thing in your while (true) loop, and [pool release]; as the last thing in it, and see if that solves the issue. That way, you'll be creating your own pool and draining it on every run through your run loop.
Quote this message in a reply
Moderator
Posts: 133
Joined: 2008.05
Post: #5
If you are only using a CFRunLoop (not a NSRunLoop), an autorelease pool isn't going to be created for you. You should allocate a pool before you break off in to any Objective-C methods and release it at the end of your loop.
Quote this message in a reply
⌘-R in Chief
Posts: 1,258
Joined: 2002.05
Post: #6
I'll just mention the possibility of re-architecting the design so you don't service the run loop from a hard loop, but rather do the opposite.
Quote this message in a reply
Member
Posts: 65
Joined: 2009.03
Post: #7
Thanks for the tips guys.

I have moved from a tight loop to NSTimer and that made no difference to the memory leak, so I added my own NSAutoReleasePool at the start of the method and released it at the end and the leak has gone.

Seth, I'm not sure if moving to an NSTimer was what your were talking about in your post. I've not noticed any performance hit from creating and releasing my own autorelease pool, but if anyone has any comments on the approach I'd welcome the input.

Thanks again

MikeD
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Memory leak via obj-c markhula 4 4,900 Apr 17, 2011 01:35 PM
Last Post: SethWillits
  Why Does OpenGLES Appear To Leak Memory? muleskinner 2 3,532 Oct 22, 2009 04:54 AM
Last Post: muleskinner
  stringWithFormat or initWithFormat ? Bracer 5 3,680 Oct 13, 2009 01:24 PM
Last Post: ThemsAllTook
  PNG memory leak question JYoung 0 1,928 Aug 15, 2009 07:50 PM
Last Post: JYoung