Objective-C - Instruments shows leak for array, even with ARC - objective-c

The following function shows a leak in Instrument (Leak) - Xcode, even with the code commented out as shown below.
void function () {
NSArray *devices = [AVCaptureDevice devices];
// I have used devices here..but I commented to check leak.
devices = nil;
}
Responsible library is AVFoundation. I'm using ARC.

Instruments doesn't show where objects are being leaked - it shows where the object that is being leaked is being created.
What you can do is to look at how you manage the memory of devices and make sure that you are releasing it correctly.
It's odd that it's showing a leak under ARC - so it would be useful to see some relevant code to see what is being done.

Related

Creating autoreleased object inside GLKViewController run loop causes malloc error

I'm currently using GLKit to do some OpenGL drawing. I created a normal UIViewController and then added a GLKViewController subclass inside a container to do my drawing. While everything runs fine initially, if I let my program run for a period of time (perhaps 15-30 minutes), eventually it crashes and gives me the following error.
malloc: *** mmap(size=2097152) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
So I turned on the malloc_error_break breakpoint, and the stack trace points to the following code.
-(NSArray*)meshes:(NSArray *)meshes sortedFromFrontToBack:(BOOL)sortedFromFrontToBack
{
NSMutableArray *sortedMeshes = meshes.mutableCopy;
[sortedMeshes sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
DSNode *mesh1 = obj1;
DSNode *mesh2 = obj2;
GLKVector3 depth1 = isnan(mesh1.boundingSphere.radius) ? mesh1.transformationState.position : mesh1.boundingSphere.center;
GLKVector3 depth2 = isnan(mesh2.boundingSphere.radius) ? mesh2.transformationState.position : mesh2.boundingSphere.center;
GLKMatrix4 mesh1ToCameraSpace = [mesh1 nodeToOtherNodeTransform:self];
GLKMatrix4 mesh2ToCameraSpace = [mesh2 nodeToOtherNodeTransform:self];
GLKVector3 depth1InCameraSpace = GLKMatrix4MultiplyVector3WithTranslation(mesh1ToCameraSpace, depth1);
GLKVector3 depth2InCameraSpace = GLKMatrix4MultiplyVector3WithTranslation(mesh2ToCameraSpace, depth2);
NSNumber *n1 = [NSNumber numberWithFloat:depth1InCameraSpace.z];
NSNumber *n2 = [NSNumber numberWithFloat:depth2InCameraSpace.z]; /* Breakpoint triggered here */
if(sortedFromFrontToBack)
{
return [n2 compare:n1];
}
return [n1 compare:n2];
}];
return sortedMeshes;
}
As I commented, the [NSNumber numberWithFloat:] call throws the malloc error. This method gets called once each frame from my GLKViewController's drawInRect method. Essentially, I have a class which keeps track of my cameras and the meshes which are going to be drawn by OpenGL, and it sorts them in camera space from either front to back for opaque meshes or back to front for transparent before drawing them.
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(self.clearColor.r, self.clearColor.g, self.clearColor.b, self.clearColor.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DSDirector *director = [DSDirector sharedDirector];
for(DSMesh *mesh in director.opaqueMeshes)
{
[mesh draw];
}
/* The director class keeps track of my scene's cameras and meshes and calls the above method to return the scene's transparent meshes properly sorted */
for(DSMesh *mesh in director.transparentMeshes)
{
[mesh draw];
}
}
From what I've read, the autorelease pool should drain at the end of each run loop, so I wouldn't think that creating a bunch of autoreleased objects every frame is an issue, they should all get flushed each frame. I've profiled my program and checked for any leaks and can't find any, and I'm using ARC as well, which should minimize the risk. When I profile it, the live bytes total never budges, although the overall bytes rises quite quickly, and no leaks are found. In addition, didReceiveMemoryWarning never fires. I'm stumped.
Something smells wrong about the NSNumber creation being the cause of your malloc error. Testing with Instruments might help find the real culprit.
However, you're doing two things you don't need to, so there's some chance that eliminating them might help with your problem.
First, you don't need to wrap floats in an NSNumber to compare them. The basic comparison and mathematical operators work just fine, and don't require extra time or memory for object creation:
if (depth1InCameraSpace.z < depth2InCameraSpace.z)
return NSOrderedAscending;
else if (depth1InCameraSpace.z > depth2InCameraSpace.z)
return NSOrderedDescending;
else
return NSOrderedSame;
Second, the Tile-Based Deferred Rendering strategy implemented by the GPU hardware on iOS devices does its own hidden surface removal optimizations -- sorting opaque geometry front to back is redundant, so all it does is waste CPU time. (There's a decent explanation of this is in the OpenGL ES Hardware Platform Guide for iOS.) You should still sort translucent geometry back to front (and draw it after opaque geometry) for proper blending, though.
So, I think I've figured out what was going on. At some prior point I'd enabled NSZombies and then forgot about it, and so all of my objects that I expected to be deallocated were actually still hanging around. When profiling in Instruments, zombies must not be counted as live, which is why I couldn't figure out why I was seemingly running out of memory when the number of live bytes wasn't climbing. However, when I upgraded to XCode 5, the new memory gauge showed that I was quickly racking up memory, and then when I dropped into Instruments, Leaks was covered up by a warning that said that it would not work properly since NSZombies were enabled. So, I disabled zombies, and now my memory usage is staying constant, just like I expected it to.

passing objects from no arc compiled class to arc enabled class?

I ran into this problem while trying to fix a memory leak with the facebook-ios-sdk. How do i handle this situation when passing objects from no arc compiled classe to arc enabled classe?
This is the code inside the non arc compiled Facebook library: (i removed the unnecessary stuff which is not related to the problem) as you can see, result object is not autoreleased or released.
- (void)handleResponseData:(NSData *)data {
NSError* error = nil;
id result = [self parseJsonResponse:data error:&error];
self.error = error;
// Call the defined delegate wich is my AppDelegate didLoad method wich is arc enabled
[_delegate request:self didLoad:result];
}
- (id)parseJsonResponse:(NSData *)data error:(NSError **)error {
SBJSON *jsonParser = [[SBJSON alloc] init];
//gets the object wich leaks or gets overreleased
id result = [jsonParser objectWithString:responseString];
[jsonParser release];
return result;
}
Now if i try to add autorelease to the result object, i am facing a NSZombie when my arc code in my AppDelegate try's to release the object. However if i leave the code like this i'm facing memory leaks whit the result object which gets not released.
am i missing something basic? i can't get my head around this?
Thanx for any advice! Chris
The result returned from -parseJsonResponse:... is autoreleased already (see note at bottom).
Since the name of the -parseJson method doesn't begin with new, alloc, copy or mutableCopy, the compiler assumes that it returns an object with a +0 reference count, meaning it needs to be retained by the calling code if it is to be kept around, and doesn't need to be released if it's not being kept around. That's a long winded way of saying that it should neither leak nor cause a crash in your ARC code as written in your question.
Passing objects between ARC code and manual reference counting code doesn't require any special handling. You just need to make sure that methods' names match their memory management semantics in the non-ARC code. It certainly seems like you've done that in this case, although as you say, you didn't post your complete code.
Note: Presumably, objectWithString: returns an autoreleased object. If it doesn't it, it should (because it doesn't start with alloc, new, copy, mutableCopy).

Instruments not detecting a memory leak in Xcode

I have been puzzling over this for days now. I'm still trying to wrap my head around memory management in objective-c.
Here is my snippet (condensed for clarity):
- (void)performOperation:(NSString *)operation
{
if ([#"+" isEqual:operation])
{
waitingOperation = operation;
}
else if ([#"C" isEqual:operation])
{
waitingOperation = nil;
}
}
waitingOperation is merely a local private NSString (no #property, no #synthesize, no getters/setters).
Shouldn't I be leaking memory when I assign waitingOperation to nil when it's currently pointing to an NSString on the heap? My call to this method is in an ios app that is passing NSString from UILabel display.text. I've been profiling this code with Instruments and I never see any leaks. I would really appreciate some clarity on this. Thanks in advance.
You haven't laid a claim of ownership on waitingOperation by calling retain, so you have no responsibility to release.
This may lay you open to problems at some point if the string is released elsewhere (by disposing of the UILabel for example), in which case you'll be left with a dangling pointer. But you aren't leaking anything here.

NSString Copy Memory Leak

I have an app that leverages the TouchJSON objective-C library and I'm running the Instruments profiler for memory leaks and getting a leak in that source that I can't figure out how to fix. I should mention that I'm fairly new to Cocoa and objective-C. Instruments is showing that the leak occurs in a method with the following signature:
- (BOOL)scanJSONStringConstant:(NSString **)outStringConstant error:(NSError **)outError
...and the leak is specifically occurring in this block of code:
if (self.options & kJSONScannerOptions_MutableLeaves)
{
*outStringConstant = [theString autorelease];
}
else
{
*outStringConstant = [[theString copy] autorelease]; //LEAK IS HAPPENING HERE
[theString release];
}
I've tried a variety of fixes to try and get rid of the leak but with no success. Can someone please educate me on:
1) Why this is a leak
...and...
2) How to fix it
I'm familiar with the rudiments of objective-C memory management ("If you alloc, copy, or new...release is up to you") so I don't need a whole primer on the basics - just some insight as to why this is leaking.
Thanks in advance for any help.
EDIT: Attaching image of debug info.
What Instruments is telling you isn't that the leak occurred at that line, instead it's telling you that the object created at that line was leaked.
I would look again at the client code that uses the scanJSONStringConstant method and review its memory management. Is there a logical flow where it may miss a release call on the outStringConstant pointer?
change this line *outStringConstant = [[theString copy] autorelease];
TO
if(*outStringConstant)
[*outStringConstant release];
*outStringConstant = [NSString stringWithString:theString];
[theString release];

Leak in NSScanner category method

I created an NSScanner category method that shows a leak in instruments.
- (BOOL)scanBetweenPrefix:(NSString *)prefix
andSuffix:(NSString *)suffix
intoString:(NSString **)value
{
NSCharacterSet *charactersToBeSkipped = [self charactersToBeSkipped];
[self setCharactersToBeSkipped:nil];
BOOL result = NO;
// find the prefix; the scanString method below fails if you don't do this
if (![self scanUpToString:prefix intoString:nil])
{
MY_LOG(#"Prefix %# is missing.", prefix);
return result;
}
//scan the prefix and discard
[self scanString:prefix intoString:nil];
// scan the important part and save it
if ([self scanUpToString:suffix intoString:value]) // this line leaks
{
result = YES;
}
[self setCharactersToBeSkipped:charactersToBeSkipped];
return result;
}
I figure it's the way I'm passing the value to/from the method, but I'm not sure. It's a small leak (32 bytes), but I'd like to do this right if I can. Thanks in advance.
I found the answer. I had a model class that used the result of the code above, but forgot to release the property in the dealloc method. I should have caught it with Instruments, but I didn't know where to look. I got caught up in the call stack in the Extended Details, which had only part of the info I needed.
For morons like me, here's what I did:
Run your app with Instruments ... Leaks.
In Instruments, watch the leaked blocks view (the grid icon at the bottom) and turn on the extended detail.
If you have multiple leaked objects, click the disclosure triangle so you can look at a discrete address.
Next to an address, there will be a detail arrow. Click on it.
Now you'll be looking at history. It starts with Malloc and shows you each retain and release.
You should have a release for the malloc and a release for every retain in the history. Match up your retains and releases and look for the oddball. When in doubt, look toward the bottom of the page and carefully review any properties you may have forgotten to release in your dealloc method(s).
OK, I'm stupid. This method does not leak. The leak is farther down my call stack, but I can't figure out where. Sorry for the premature post. I'll follow up when I figure out where the real leak is, if I can't figure out the fix myself.
In answer to Yuji's comment, my method call is:
NSString *title;
[fileScanner scanBetweenPrefix:kTitlePrefix
andSuffix:kTitleSuffix
intoString:&title];
Is it the &title that's the problem? I patterned it after the existing NSScanner methods and calls.