Noob: Cant Find a Memory Leak in Texture Engine

Member
Posts: 21
Joined: 2007.09
Post: #1
I have adapted the following code from gamewiki and some other source.

I am trying to call this method to load up sequences of very large tiles to show an action. Then destroy the texture and free the memory before calling up the next action.

Based on code performance and the MallocDebug I am pretty sure there is a memory leak here but I can't figure it out. Any Ideas?
Code:
- (void)textureEngine: (GLboolean)firstMethodCall:(NSString *)imagename:(int)i:(int)angle{

    CGImageRef image;
    CGImageSourceRef theSource;
    CGDataProviderRef provider;
    CFStringRef path;
    CFURLRef url;
    size_t myCount=IMAGE_COUNT+1;
    
    NSString *filename;
    
    if(!firstMethodCall){free(image_base);}
    
    image_base = (GLubyte *) calloc(myCount ,image_size * image_size  * (IMAGE_DEPTH >> 3));
    
    filename = [[[NSBundle mainBundle] pathForResource:imagename ofType:@"png"] cString];
    path = CFStringCreateWithCString (NULL, filename,kCFStringEncodingUTF8);
    url = CFURLCreateWithFileSystemPath (NULL, path,kCFURLPOSIXPathStyle, NULL);
    CFRelease(path);
    provider = CGDataProviderCreateWithURL (url);
    CFRelease (url);
    
    theSource = CGImageSourceCreateWithDataProvider(provider, NULL);
    image =    CGImageSourceCreateImageAtIndex(theSource,0,NULL);    
    
    width = CGImageGetWidth(image);        
    height = CGImageGetHeight(image);        
    
    data[i] = image_base + i * (width * height * 4);
    GLint dt = i+1;  //signedness issue??
    
    CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(data[i], width, height, 8,width * (IMAGE_DEPTH >> 3), color_space, kCGImageAlphaPremultipliedFirst);
    CGContextDrawImage(context,CGRectMake(0, 0, width, height),image);
    
    [[self openGLContext] makeCurrentContext];
    [[self openGLContext] update];
        
    if(!firstMethodCall){glDeleteTextures(1, &dt);}
        
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_TEXTURE_RECTANGLE_EXT);
    glBindTexture(GL_TEXTURE_RECTANGLE_EXT, dt);
        
    if(texture_range) glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, (IMAGE_COUNT+1) * width * height * (IMAGE_DEPTH >> 3), image_base);
    else              glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, 0, NULL);
        
    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE , texture_hint);
    glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, client_storage);
    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, width,height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data[i]);
        
    
    CFRelease(context);
    CFRelease(color_space);
    CFRelease(image);
    CFRelease(theSource);
    CGDataProviderRelease (provider);

}
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
Where does leaks say your leaks are?

Does OpenGL profiler say you have an ever-increasing number of texture objects?
Quote this message in a reply
Member
Posts: 21
Joined: 2007.09
Post: #3
Thanks for the reply.

I should state that after I diagnosed the problem I saw your post of a few days ago and switched

Code:
image_base = (GLubyte *) malloc (myCount * image_size * image_size  * (IMAGE_DEPTH >> 3));

to

Code:
image_base = (GLubyte *) calloc(myCount ,image_size * image_size  * (IMAGE_DEPTH >> 3));


which seems to have helped, although I did not realize it because the performance still drags. As of right now MallocDebug is telling me that there is a leak at MDCalloc, but this does not appear to be growing with calls to the texture engine. From what I can tell OpenGL profiler is showing 13 textures in the resources window after every call so I think that is a good sign too.

I have a suspicion the problem is the speech recognizer I implemented elsewhere.

Thanks for the tips.

UDPDATE:

No, not the speech recognition... Now MallocDebug is finding the leak grows from a source called "start" under NSApplicationMain. I trace this down to MDCalloc in the standard view.

hmmm...

Well it doesn't appear to be an OpenGL thing at any rate.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
You never free(image_base), that's your leak.

Calling calloc rather than malloc won't've changed anything except the behavior when loading transparent images.
Quote this message in a reply
Member
Posts: 21
Joined: 2007.09
Post: #5
OneSadCookie Wrote:You never free(image_base), that's your leak.

Here is where I thought I free image_base after the first method call.

Code:
if(!firstMethodCall){free(image_base)};

the idea being that every subsequent call will free before allocating it again.

On the other hand

When I simply append the method with...

Code:
free(image_base);

at the end, I get an exception.
Quote this message in a reply
Member
Posts: 567
Joined: 2004.07
Post: #6
that's because you free the image_base before you ever allocate memory for it. Just return if firstMethodCall is NULL, and free the image_base in the last line of your function. (at the VERY last line of your function), free(image_base).

in plain code:

Code:
- (void)textureEngine: (GLboolean)firstMethodCall:(NSString *)imagename:(int)i:(int)angle{

    CGImageRef image;
    CGImageSourceRef theSource;
    CGDataProviderRef provider;
    CFStringRef path;
    CFURLRef url;
    size_t myCount=IMAGE_COUNT+1;
    
    NSString *filename;
    
    if(!firstMethodCall){return;}  // if firstMethodCall is NULL, get out of the function.
       //You might want to a) return an error value, or b) check whether image_base is NULL and error on that.
    
    image_base = (GLubyte *) calloc(myCount ,image_size * image_size  * (IMAGE_DEPTH >> 3));
    
    filename = [[[NSBundle mainBundle] pathForResource:imagename ofType:@"png"] cString];
    path = CFStringCreateWithCString (NULL, filename,kCFStringEncodingUTF8);
    url = CFURLCreateWithFileSystemPath (NULL, path,kCFURLPOSIXPathStyle, NULL);
    CFRelease(path);
    provider = CGDataProviderCreateWithURL (url);
    CFRelease (url);
    
    theSource = CGImageSourceCreateWithDataProvider(provider, NULL);
    image =    CGImageSourceCreateImageAtIndex(theSource,0,NULL);    
    
    width = CGImageGetWidth(image);        
    height = CGImageGetHeight(image);        
    
    data[i] = image_base + i * (width * height * 4);
    GLint dt = i+1;  //signedness issue??
    
    CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(data[i], width, height, 8,width * (IMAGE_DEPTH >> 3), color_space, kCGImageAlphaPremultipliedFirst);
    CGContextDrawImage(context,CGRectMake(0, 0, width, height),image);
    
    [[self openGLContext] makeCurrentContext];
    [[self openGLContext] update];
        
    if(!firstMethodCall){glDeleteTextures(1, &dt);}
        
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_TEXTURE_RECTANGLE_EXT);
    glBindTexture(GL_TEXTURE_RECTANGLE_EXT, dt);
        
    if(texture_range) glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, (IMAGE_COUNT+1) * width * height * (IMAGE_DEPTH >> 3), image_base);
    else              glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, 0, NULL);
        
    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE , texture_hint);
    glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, client_storage);
    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, width,height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data[i]);
        
    
    CFRelease(context);
    CFRelease(color_space);
    CFRelease(image);
    CFRelease(theSource);
    CGDataProviderRelease (provider);
        free(image_base); // Free the allocated memory here.
}

It's not magic, it's Ruby.
Quote this message in a reply
Member
Posts: 21
Joined: 2007.09
Post: #7
Nayr Wrote:that's because you free the image_base before you ever allocate memory for it. Just return if firstMethodCall is NULL, and free the image_base in the last line of your function. (at the VERY last line of your function), free(image_base).

I was not clear. When I free at the last line I eliminate the firstMethodCall switch from my code. So no I am not freeing before I allocate.

I do think I solved the problem however:

I should have freed data[i] and image_base so now I use:

Code:
    if(!firstMethodCall){
        
        free(image_base);
        free(data[i]);
    
    }

I have to run the tools but the performance is 100% better.

I am still puzzled why I am getting the error when I free image_base conventionally at the very last line. I wonder if it has to do with the fact that glTextureRangeAPPLE is holdling onto a pointer to image_base???


Thanks for everyone's input, anyway
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #8
Yeah, you're using client storage which means you gotta keep the image data around. Sorry.
Quote this message in a reply
Member
Posts: 21
Joined: 2007.09
Post: #9
OneSadCookie Wrote:Yeah, you're using client storage which means you gotta keep the image data around. Sorry.

No Apologies necessary. I always learn something from your replies. Thanks again
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Can someone help a 'noob'? What's wrong with this? RagingAvatar 7 4,137 Jun 4, 2006 11:54 PM
Last Post: Fenris
  Small nooB question. hyperzoanoid 3 2,694 Apr 25, 2003 10:23 AM
Last Post: DoG