4

I have a problem with NSImages leaking memory when I draw to them with lock/unlockfocus. The leak goes away when I comment out the LEAKS HERE code below. So I know that is where the leak is happening.

for(int i= 0; i < nNumberImages; ++i)
{
    m_apNSImageArray[i]= [[NSImage alloc] initWithSize:m_viewRect.size];        
    if(!m_apNSImageArray[i])
    {
        return;
    }  

    //LEAKS IN THIS CODE HERE
    [m_apNSImageArray[i] lockFocus];

    //EDIT: Commented the lines below out, but leak persists.    
    //[[[[NSApp delegate] getColors] getAudioWaveColor:YES] setStroke];        
    //[[m_pmaBezierPaths objectAtIndex:i] stroke];    

    [m_apNSImageArray[i] unlockFocus];      
    //TO HERE        
}

I'm using garbage collection, and this for-loop is part of an NSOperation running in an NSOperationQueue in OSX 10.7 Lion.

Is this a bug with NSImage's lockfocus on background threads/operations?

EDIT: It appears that lockFocus is allocating new space each time its called.

Mark
  • 408
  • 3
  • 12
  • Do you ever release the image? – Chuck Aug 18 '11 at 01:07
  • Hi Chuck, thanks for the comment. I don't release the image directly because I'm using garbage collection (gc), but I do set each element in the NSImageArray to nil a bit before I call the code above, which with gc signals collection. – Mark Aug 18 '11 at 01:15
  • And I tried not making new NSImages inside the for-loop. Instead I only made them once, but then I couldn't get the NSImageRep caches to clear, and the lockFocus unlockfocus code still leaked at the same rate. – Mark Aug 18 '11 at 01:42

3 Answers3

2

I had a nearly identical issue and needed to add an autorelease pool.

Non-ARC:

// set up the autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// do image stuff
NSImage *imagemage = [[NSImage alloc] init];
[maskedImage lockFocus];
[maskedImage unlockFocus];
[image release];

// drain the autorelease pool
[pool drain];

ARC:

@autoreleasepool {
    NSImage *imagemage = [[NSImage alloc] init];
    [maskedImage lockFocus];
    [maskedImage unlockFocus];
}
Brandon
  • 953
  • 10
  • 12
  • For those who encounter this problem in Swift, autoreleasepool { } without the "@" may be needed to eliminate messages such as "Context leak detected, CoreAnalytics returned false" that occur for NSImage.lockFocus() and .unlockFocus(). See also https://swiftrocks.com/autoreleasepool-in-2019-swift – Rethunk Apr 15 '21 at 12:40
0

Well I still am not totally sure how to stop the leak completely, but I drastically reduced the number of times I lockFocus/unlockFocus. This essentially solved my problem.

Mark
  • 408
  • 3
  • 12
-1

I'd look at your -getColors and -getAudioWaveColor: methods.

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • Hey Caleb, thanks for your answer. Those methods are very simple, but to test it I just commented the line ([[[[NSApp delegate] getColors] getAudioWaveColor:YES] setStroke];) out and the leak persists at the same rate. – Mark Aug 17 '11 at 21:47
  • If you're detecting the leak with Instruments, you should be able to see what objects are leaking. That should give you a clue as to where they're coming from. – Caleb Aug 17 '11 at 21:49
  • I was using Activity Monitor (AM) to track my systems memory, but I just used Instruments' Leaks tool to try and find the leak and it didn't find any. That's strange considering I can see the memory usage go up each time I trigger the call to this code in AM. – Mark Aug 17 '11 at 22:09
  • 1
    If the Leaks tool doesn't show a memory leak, then the memory you're seeing "leaked" may just be `retain`/`autorelease`d and waiting for gc to pick it up. –  Aug 19 '11 at 00:42
  • Hey DarvidsOn, you may be correct, but how long should it take for memory to be collected? – Mark Aug 19 '11 at 18:01