XCode 4 + Instruments 4: False positive leaks? - objective-c

Ever since switching to XCode 4 the leaks tool shows a LOT of leakage, all from JSONKit and ASIHTTPRequest, after a 2 min run I am leaking hundreds of arrays/dictionaries/strings (from jk_create_dictionary, jk_parse_array, HTTPMessage::*, etc.) totaling a few 100s KB. Most of the stack traces don't originate in any of my calls, and the rest are completely innocent.
I am pretty positive it was not the case pre-XCode 4.
I don't know who the culprit is. Any insight would be lovely.
Update:
The JSONKit leaks are probably JSONDecoder caching.
For example:
static JSONDecoder *decoder = nil;
if (!decoder)
decoder=[[JSONDecoder alloc] init];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setCachePolicy:ASIDoNotWriteToCacheCachePolicy];
[request setCompletionBlock:^{
NSData *response = [request responseData];
NSDictionary *json = [decoder objectWithUTF8String:[response bytes] length:[response length]];
// ...
}];
[request setFailedBlock:^{
// ...
}];
[request startAsynchronous];

EDIT : Before you read the rest of this answer:
If you see that kind of memory leaks, don't blame Instruments or JSONKit... Both are reliable!
...Blame yourself, 99.9% chances your code is leaking the data you parsed with JSONKit!
END_OF_EDIT
Not an answer, more a complement, and an attempt to understand what's going on since I'm seeing leaks too with instruments.
I'm using JSONKit that way :
NSArray *lines = [dataString componentsSeparatedByString:#"\n"];
for (NSString *line in lines) { // I know, strange format isn't? :)
NSDictionary *json = [line objectFromJSONStringWithParseOptions:JKParseOptionLooseUnicode];
// use dictionary data...
}
#ssteinberg, is that the kind of leaks you're having? :
Note that I had this after some heavy load testing, 500 requests with huge JSON responses, which explains leaks are in MB (using latest gh version)
Please note that I'm quite new using Instruments, and I'm not sure how to understand these results. According to Frames reported, yes that looks like Caching... but I'd like to be sure...
So I opened an Issue on GH, I hope that #johnezang, or anyone, will enlight us about this.
All my apologies if that's just a misunderstanding with Instruments, which I would prefer :)

According to Apple's WWDC 2010 videos (Advanced Memory Analysis with Instruments), false positive leaks are rare. Sometimes the Leaks tool misses leaks, but it's reliable for the ones it reports. I'm not all that great with statics, but have you checked to make sure you're not alloc'ing the decoder without releasing it? If it's not released and falls out of scope, that would constitute a leak, right?

Related

NSURLConnection messes up iPad memory

we build an iPad app that downloads a bunch of data and PDF documents from a web service (data first, documents later in the background). To do so, we use SOAP via HTTP(S) requests. It works fine and altogether, the app is running well. Problem is, if there are too many documents to download at some point the app crashes. Using Instruments I figured out that it is a memory issue, particularly NSRegularExpression and NSRunLoop. (I'm using ARC)
I could improve my code to optimize the NSRegularExpression creation. But I don't know how to improve the NSRunLoop issue.
I tried both, asynchronous and synchronous HTTP request. Using async, I had to wait for the download to finish and since sleep()/[NSThread sleepForTimeInterval:] aren't an option, I use
while ( _waitToFinish ) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
Using sync request, Instruments reveals that
[NSURLConnection sendSynchronousRequest:theRequest returningResponse:&urlResponse error:&error];
also "waits" with help of NSRunLoop and also messes up the memory.
Is this a bug in CoreFoundation or ARC?
Is there another way to idle while waiting for the requests to finish?
Thanks in advance.
Edit:
With "memory issue" I meant that the app crashes (or is killed by iOS) because it uses too much memory.
This is what Instruments shows:
The percentage get higher the longer the app is downloading.
Edit:
Going further down revealed that it is NSURLConnection, that is messing up the memory. It seems that I have somehow missed setting connection and receivedData to nil (see URL Loading System Programming Guide). This improved my memory usage again a little.
Now, there are two more big memory allocation operations:
And this is the code I think belongs to what Instruments displays:
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_receivedData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseText = [[NSString alloc] initWithBytes:[_receivedData mutableBytes] length:[_receivedData length] encoding:NSUTF8StringEncoding];
self.lastResponse = responseText;
responseText = nil;
connection = nil;
_receivedData = nil;
_lastResult = TRUE;
_waitToFinish = FALSE;
}
Is there anything I could change to improve the code?
Edit: (Changed title from "NSRunLoop messes up iPad memory")
Edit:
I created a test app to prove that it is the NSURLConnection, that messes up the memory. Then I contacted the Apple Developer Support.
Since I am downloading a lot of PDF in an iteration with NSURLConnection, the solution was to add an #autoreleasepool { .. } in the iteration and another one around the NSRunLoop.
Thanks.
It's not a bug in Core Foundation or ARC. It's a bug in your code.
Don't run the run loop yourself. Just use +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]. It will call your completionHandler block when the request is complete. That's when you process the response. Meanwhile, just return out of your method and let the system worry about running the run loop.
You say “it's a memory issue” with NSRegularExpression and NSRunLoop, but you don't say what the issue is, or what evidence Instruments is showing you. If you describe the “issue” in more detail, maybe we can help you with that.

CoreData leak when reading a property

I have the following code in a loop iterating over the different document objects:
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSData* data = [document primitiveValueForKey:#"data"];
[document.managedObjectContext refreshObject:document mergeChanges:NO];
[pool release];
The "data" property is a large blob (a 1MB image).
And as I monitor the memory with the Allocation Instrument memory usage is increasing. I cannot find where the leak is coming from and how to remove it.
Thanks!
Something is wrong with your sample code, did you mean:
NSData *data = [document primitiveValueForKey:#"data"];
As data is currently not assigned within the scope of your autoreleasepool it is also not released with with your autoreleasepool
Why are you using primitiveValueForKey and not a dynamic accessor?
The dynamic accessors are much more
efficient, and allow for compile-time
checking.
How about calling [pool drain] instead of [pool release]?
I managed to solve the problem by doing : [document.managedObjectContext processPendingChanges] right before draining the pool. However, I don't understand what pending changes would be there? Could someone enlighten me on that?
Your observation that processPendingChanges seems to solve the problem suggests to me that, as you import, the UndoManager for your NSManagedObjectContext is keeping track of all the changes you make as you do your bulk import.
What processPendingChanges is doing (as I understand it) is pushing changes stored in the managedObjectContext to the persistent store.
Try [[document managedObjectContext] setUndoManager:nil] (or create a new managedObjectContext for the import and set its undoManager to nil, if your document.managedObjectContext is the 'main' managedObjectContext and you don't want to turn off undo registration.

Objective-C memory leak in loading remote content

I try to load a plist file from my server. I can think of 2 ways to do that, but for both Instruments says there's huge memory leak :
NSData* plistData = [NSData dataWithContentsOfURL:url];
and
NSDictionary* updateDigest = [NSDictionary dictionaryWithContentsOfURL: [NSURL URLWithString:updateURL] ];
The backtrace of the memory leak leads to __CFURLCache in CFNetwork and I am wondering if something can be done to fix the leak? Any other way to load a remote plist xml, without the memory leakage ?
Thanks
The leak probably isn't coming from loading the data. It's probably from retaining the data elsewhere and not releasing it.

Checking for NSURL load done

I'm looking for a "did finish, or finish" thing in NSURL -> NSstring initWithContentsOfUrl
I found "URLResourceDidFinishLoading" but this seems to be depreciated
I couldn't find any but maybe I searched for the wrong thing.
If you're talking about -initWithContentsOfURL: from NSString, it has been deprecated.
But even if you are using it, it's a synchronous method - meaning your code will halt until the data has been loaded into the resulting NSString object:
NSURL *url = [NSURL URLWithString:#"http://google.com"];
NSString *htmlData = [NSString stringWithContentsOfURL:url];
NSLog(#"%#", htmlData); // you have your data loaded here, synchronously.
So, just to be clear: this is a bad practice for two reasons:
You're using a deprecated method which will most likely be removed on future SDK versions, and;
You're freezing your UI while loading something from the network, while giving no feedback to the user whatsoever.
What you need is probably NSURLRequest to create your request object and NSURLConnection to actually load it from the network.

int / float to NSString without using alloc?

Is there anyway to get int (or float) numbers into a NSString object without using alloc and a subsequent release?
int myInt = 25;
NSString *myString = [[NSString alloc] initWithFormat:#"%d",myInt];
...
[myString release];
EDIT:
Thanks for the answers, I should have been a little more clear in the question, I am particularly interested in using this on the iPhone. As #chuck stated I could use a convenience method, but I was under the impression that I should be avoiding these where possible on the iPhone for memory / performance reasons. I could be wrong though.
gary
There's no way to create an NSString without creating it at some point. But you could use a convenience constructor so you don't have the burden of ownership.
NSString *myString = [NSString stringWithFormat:#"%d", myInt];
It will still be created and destroyed (as everything must be), but you don't have to do it yourself.
I could use a convenience method, but I was under the impression that I should be avoiding these where possible on the iPhone for memory / performance reasons.
The “performance reason” is the cost of autoreleasing an object. This was, at one time, expensive on an iPhone. (I don't know whether it still is.) The only alternative is explicitly allocating it and releasing it yourself. As others have pointed out, you can't have an object without having allocated it, and you mustn't allocate it without releasing it. You need both things to happen one way or another.
The memory reason is simply that an autoreleased object lasts longer—specifically, until the autorelease comes due. Autorelease many objects, and your memory usage will pile up; pile it up high enough, and SpringBoard will tell your app to knock it off (and/or just kill it). The solution is to make the objects not last so long, which means either (1) creating and draining your own autorelease pool around a known batch of objects or (2) managing the objects' lifetimes (that is, allocating and releasing them) yourself.
This latter reason is not specific to the iPhone—it affects the Mac as well, although our ceiling is higher: Macs have more short-term memory, plus virtual memory, so we can get away with more memory usage. Even so, we Mac programmers should also try not to waste memory, partly because paging hell wrecks one's day, and partly because we will get email from users if our apps sit too high in the Activity Monitor list.
NSString *mystring = [NSString stringWithFormat:#"Hello: %d",myint];
it should be autoreleased if you create it this way
i think the convention is that unless you see the word init or alloc in the method name then it should return an autoreleased object. i.e. the object is added to the current autorelease pool and flushed when the app advances to next stage in lifecycle
You want
NSString *aStr=[[NSNumber numberWithInt:myInt] stringValue];
It returns an autoreleased string.
You could use an NSMutableString (-appendFormat:) or a standard C-string. However, fundamentally, no, you're going to have to allocate memory somewhere.
Why not define a macro... something like
#define intString(i1) [[[NSString alloc] initWithFormat:#"%d",i1] autorelease];
put it in your prefix header.
Most of the time autorelease will have zero impact on your app's overall memory usage. You only need to be concerned with autorelease if you're accumulating many object instances. For example:
for (int i = 0; i < 1000; ++i)
{
NSString* s = [NSString stringWithFormat:#"%d", i];
...
}
That example will accumulate at least 1000 different string instances before anything is released, which is not desirable. That's a situation where you would look for alternatives.
If you wanted to avoid creating a bunch of string instances you could use NSMutableString:
NSMutableString* s = [NSMutableString stringWithCapacity:20];
[s appendFormat:#"%d", 123];
...
[s setString:#""];
[s appendFormat:#"%d", 456];
...
It's questionable whether that's any faster than simply creating and releasing separate string instances, but that pattern may fit better with what you're trying to accomplish in your code.