Another iPhone memory leak question! - iphone

I have a simple example of what I don't understand about memory management on the iPhone:
- (IBAction)AssignAndReleaseOne :(id)sender {
for (int i=0;i<10;i++) {
someString = [[NSString alloc] initWithString:#"String Assigned"];
}
[someString release];
}
- (IBAction)AssignAndReleaseTen :(id)sender {
for (int i=0;i<10;i++) {
someString = [[NSString alloc] initWithString:#"String Assigned"];
[someString release];
}
}
I would expect to get a memory leak in the first method because I alloc 10 times (or is it 11 :) with only one release, but Instruments doesn't report any errors?
Am I or is Instruments correct?
Thanks Chris.

You won't get a leak, surprisingly enough. See :
Memory issue of NSString

You should be getting the memory leak you expect.
Instruments' leak detection algorithm is expensive to run, so it is only executed after a specified amount of time (I think it's defaulted to 10 seconds). You may have to let the application run for a while before Instruments picks up the leak.

Related

Proper way to release memory allocation?

I'm a newbie when it comes to objective C, and am currently experiencing a memory leak with the following code snippet. The memory leak occurs with the 'responseObj' allocation. Whenever I try to release it similar to responseData, I get a crash.
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString* responseStr = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSMutableArray* responseObj = [responseStr objectFromJSONString];
[delegate loadGameDetails:[responseObj objectForKey:#"result"]];
[responseStr release];
[responseData release]; responseData = nil;
}
I also tried to autorelease as below, but I also get a crash:
[delegate loadGameDetails:[[responseObj objectForKey:#"result"] autorelease]];
What's the proper way for me to release this block of memory?
The problem is not in your allocation. Your are sending objectForKey: to a NSMutableArray which is actually a NSDictionary/NSMutableDictionary method. Double check what type of object objectFromJSONString really returns.
Nothing in that code is leaking. You have a possible over-release of responseData but I can't tell since the declaration and setup of it is not in scope. If it is an ivar you would typically set it to nil via the accessor (which would release it there) than directly as you have done here.
If there is a leak it is in your loadGameDetails method. What makes you think you have a memory leak? Have you run this through instruments, or used the static analyser?

Memory leak of an NSMutableArray using Instruments

According to the leak instrument in XCode it's saying this line is giving a memory leak (100%)?
self.unsentPatients = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
I'm correctly releasing etc. on dealloc (which is definitely being ran) so I don't understand where I am going wrong?
It's only a small leak and Analysis doesn't come up with anything, but nonetheless it's still a leak.
Kind regards,
Dominic
There are many things wring with this code.
I'm assuming that the property is retaining the value, then you should not assign the value the way you are doing now, but more like:
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
self.unsentPatients = temp;
[temp release], temp = nil;
or
self.unsentPatients = [[[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]] autorelease];
You should also avoid using the self. syntax in dealloc or init, which will call a mutator.
In multithreaded environment this could give problems.
So the correct dealloc would be:
- (void) dealloc {
[unsentPatients release], unsentPatients = nil;
[super dealloc][;
}

message sent to released object (never released manually)

Removed release statements. Some of them seemed to be okay, but that was probably just because other things were exploding first.
- (void)handleNowPlayingItemChanged:(id)notification {
MPMediaItem *item = self.musicPlayer.nowPlayingItem;
NSString *title = [item valueForProperty:MPMediaItemPropertyTitle];
NSNumber *duration = [item
valueForProperty:MPMediaItemPropertyPlaybackDuration];
float totalTime = [duration floatValue];
progressSlider.maximumValue = totalTime;
CGSize artworkImageViewSize = self.albumCover.bounds.size;
MPMediaItemArtwork *artwork = [item valueForProperty:
MPMediaItemPropertyArtwork];
if (artwork) {
self.albumCover.image = [artwork imageWithSize:artworkImageViewSize];
} else {
self.albumCover.image = nil;
}
titleLabel.text = title;
/*OpenEars stuff*/
}
In another question I mention the SQLite errors concerning artwork.
** Deleted error and details concerning NSZombieEnabled alert of call to released objects. **
Well don't I feel stupid. It was all memory management.
I put effort into not leaking anything, even in a temporary solution, and yet I did this...
In the code you provide I do not see any calls to retain, alloc/init, or some variation of copy. That means that you should not have a any calls to release in that method and that will be the cause of your crash. Make sure you are not over releasing in other methods and remember the basics of memory management.
You're releasing title and artwork, but they're not yours. This will lead, soon or later, to a tentative to release an already deallocated object (from item's dealloc or somewhere else).
// [artwork release];
//[title release];
comment those since those are autoreleased object

NSMutableArray and property leaking memory

I am in memory-leak cleanup mode on my latest app, and have come across something that I am unable to solve.
the following method has been cleaned up except for 1 nagging issue. Instruments tells me that my NSMutableArray called itemsToKeep is leaking memory, at the point that I am creating the object. Any ideas on why I am leaking memory would be most appreciated.
Here are some notes on retainCounts:
entering the method: self.myList has retainCount = 1
exiting the method: self.myList has retainCount = 2 and itemsToKeep has retainCount= 2.
I can easily do a [itemsToKeep release] at the end which brings both counts down to 1, but the app crashes after a while (and I think I know why).
Does anyone know how I can get rid of the memory leak for itemsToKeep?
Thanks.
-(void)parsedScores:(BOOL)shouldAdd {
//trim space, tab, newline from both ends
NSString *tmp = self.lblCurrentName.text;
NSString *list = [self trimString:tmp];
NSString *separators = #",";
[self.myList removeAllObjects]; // doesn't impact retain counts
self.myList = (NSMutableArray *)[list componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:separators]]; //this bumps up the self.myList retain count to 2
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:30];
for (NSString *item in self.myList) {
NSString *tmpItem = [self trimString:item];
if (! [self shouldRemoveItem:tmpItem]) {
[itemsToKeep addObject:tmpItem];
}
}
self.myList = itemsToKeep; //makes both variables' retain counts = 2
}
I can't see a leak in the method you've provided, so I assume it's happening elsewhere. You should check if self.myList is retained somewhere else without it being released.
Also, you probably shouldn't be looking at the retain count for debugging purposes. The retain count can be misleading because it doesn't matter how many times an object is retained as long as it's released an equal amount of times.

iPhone Memory Debugging

I'm using Instruments to try to determine if there are places in my application that I could be more efficient with use of memory. I've taken the time to get somewhat familiar with Instruments but I'm generally a newbie with hunting memory management issues having come from a Java background. I seem to be using about 1.82mb by calls to this method:
+ (NSString *)stringFromDateWithFormat:(NSDate *)date withFormat:(NSString *)format
{
NSDateFormatter *dateFormatter;
NSString *result;
if (nil == date || nil == format)
return nil;
result = nil;
if (nil != (dateFormatter = [[NSDateFormatter allocWithZone:[self zone]] init])) {
[dateFormatter setDateFormat:format];
if (nil != (result = [dateFormatter stringFromDate:date])) {
[dateFormatter release];
return result;
}
[dateFormatter release];
}
return nil;
}
As I'm releasing the date formatter I'm wondering if the NSString result is my issue. It seems to me that the stringFromDate library call would return an autoreleased object so there's nothing I can do to 'manually' manage it. A bit unsure of how to optimize this method.
Is this method getting called a lot of times in a loop? Autoreleased objects only get released when the NSAutoreleasePool they're in gets released. As I understand it, the default autorelease pool is created and release every event loop. It's possible you're creating too many autoreleased objects in the course of a single event loop. The solution is to create your own NSAutoreleasePool in an appropriate place, and release it to clear up autoreleased objects. An extreme example that illustrates the point:
int i;
NSAutoreasePool* pool = nil;
for (i = 0; i < 1000000; ++i) {
/* Create a new pool every 10000 iterations */
if ((i % 10000) == 0) {
if (pool) [pool release];
pool = [[NSAutoreleasePool alloc] init];
}
[someObj someMethodThatCreatesAutoreleasedObjects];
}
[pool release];
In that example, the current pool is released every 10,000 iterations and a new one is created. You can read more about memory management in the Memory Management Programming Guide section on autorelease pools.
You need to return an autoreleased object anyway, so there's really nothing you should be doing about the result string. I don't see any mistakes related to memory, but your code is definitely more verbose than needed. Keep in mind that in Objective-C, if you call a method on nil, you get back nil (or 0 for an integer, but not for floating point values). You can take out all those if statements and the two return paths, and your code will still work the same way. Also, I would just use alloc instead of allocWithZone.
I am not a 100% with this. I am also just learning Mac/Iphone development. But you can use the auto release pool to help with memory management. It is used to get around release problems.
Here is an article with lots on memory management. Check out the left sided menu.