why is there a memory leak in the SimpleEKDemo code? - iphone

When profiling the SimpleEKDemo application from Apple I note there are some memory leaks.
One of the leaks is __NSArrayM which has 3 lines in the Leaked Blocks history, a Malloc/Assign/Release.
Question - can someone point out the root cause issue here? (I'm trying learn how to take Instruments output of where a leaky object was created, and then from there work out root cause, so this would be really useful)

You will notice that when you run the demo with leaks that there is a leak in viewDidLoad (responsible frame). If you switch to Call Tree detail and if you have enabled Invert Call Tree, you will see a leak associated with the call +[NSArray new]. If you open that a bit, you will see initWithArray which is called in the RootViewController's viewDidLoad. The problem bit is,
self.eventsList = [[NSMutableArray alloc] initWithArray:0];
eventsList is a retained property so the object created has a retain count of 2. However it is only released once either through the release in dealloc or through reassignment of eventsList. YOu will have to autorelease this object.
self.eventsList = [[[NSMutableArray alloc] initWithArray:0] autorelease];
Once fixed, you shouldn't get any errors.

Related

Detecting C leak using Instruments (Leaks)

I wrote a test code to check how to use Instrument (Leaks). I have created a single view application and on a button click I have loaded a new view like this...
- (IBAction)btn_clkd:(id)sender {
new_file *new = [[new_file alloc] init];
if (new) {
[self.navigationController pushViewController:new animated:YES];
new = nil;
}
}
In new_file ViewDidLoad method, I have create a leak like below...
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
char *c_mem = (char*) malloc(10000000);
strcpy(c_mem, "TESTING");
// free(c_mem);
}
Even I'm using ARC, memory allocated is a plain C malloc, and I have not freed memory after used, even though I have popped and loaded again and again the new view, instrument(Leaks) is not detecting any leak in this code... What is the reason, Am I checking correctly?
Thanx
Given your view controller is deallocated (please verify), eventually Leaks will detect that c_mem pointer leaks.
Instruments may not find this immediately - due to the algorithm it uses to detect leaks.
The algorithm is basically searching for unreferenced variables looking like pointers which point into the heap. If it happens that there is an arbitrary variable, say p, whose value happens to be the value of c_mem - then Instruments thinks that pointer c_mem is still referenced from p -- even though p may contain only arbitrary data and not referencing c_mem.
Note that Instruments leak detecting algorithm is actually more sophisticated, and may change and get improved.
In order to find leaks, I always run special code - like unit tests - in a loop. If the used memory does not grow in time, you are usually good. You can also use the "Snapshot" feature of Leaks, and the "Mark Generation" feature of Allocations to check for the current state of the heap.
When you pop your ViewController, if nothing has references to it, it is deallocated automatically by ARC with all it's variables. That is why you do not get leaks.
Look at what happens to your controller, when you pop it, using Leak Instrument. Also you can see there a number of references on it. It is very convenient to detect retain cycles also.
Here is a full reference on how to use Instruments.

Memory leaks caused due to CoreFoundation Framework

I am developing an iPhone application which mainly makes use of the Address Book and database. After fetching about 3000 contacts from the address book, I am attaching string tags to the contacts (5 for each). I am saving my tags in the database.
For Load testing purpose i have added 10,000 tags to the App. But during the load testing of my application, I observed some memory leaks which were not related to the Application code but represents a set of Instruction sets. Also Instruments showed Foundation as the responsible library for the Leak (Extensive use of NSString,NSDictionary,NSArray which belongs to the Foundation framework). My application crashes after 10 - 15 mins of usage.The Crash report mentions, application crashed due to low memory.
Memory profiling using CLANG shows zero leaks. How do i solve these memory leaks?
Are these leaks the real culprit behind the crash? Are there any other tools available to check memory leaks?
I often find my leaks say they're caused by Core Foundation (or any other framework for that matter) but are really my own. With the exception of the Simulator, rarely will you find excessive leaking in the frameworks.
If you open up the detail panel to the right in Instruments you may find listed your App's methods in there. That will give you indication of where it could be coming from in your code. One leak can spring many other leaks, and you may have to find the top level culprit to get rid of the lower level ones.
You should not expect Clang to do anything but find the most obvious leaks. It's very handy, but that's it, just a helpful addition to compiling.
clang is not a leak checker. It only detects a small subset of issues.
For memory leak debugging you should focus on Instruments, specifically the Object Allocation and Leaks instruments. Be sure to understand the difference between leaks and other source of high memory usage though.
Once you've determined that objects are leaking, use Instruments to examine their allocation stack trace (so you can tell what object it is), and their retain/release history.
If it's not a leak, then I suggest investigating the instructions here:http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
Most likely you have code that is creating the foundation objects. Leaks shows you the place of allocation but that is generally due to a call your code made to create the object. You can look at the call chain in Instruments and go back along the call chain until you get to your code - that is the place where you are causing the allocation. Now, for that allocation, look at your memory handling for that object: Do you release it some time later?
There are lots of ways you can fail to release memory property so it would be hard to guess which one you might be hitting. Ones I see when helping people include allocating an object and assigning it to an instance variable via a property with the retain attribute, something like this:
#property (retain) NSString* myString;
...
self.myString = [[NSString alloc] initWithString: #"foo"];
the alloc+init creates a retained object, the self.myString = increments the retain count again. If coded correctly, the dealloc method releases the property via one of:
[myString release];
or
self.myString = nil;
And that takes care of the retain added with the self.myString = but does NOT take care of the retain from creation. Solutions, ONE of the following:
myString = [[NSString alloc] initWithString: #"foo"]; // doesn't call the setter method so no assignment retain - but doesn't call the setter which might be bad if non-trivial setter.
self.myString = [[[NSString alloc] initWithString: #"foo"] autorelease];
autorelease releases the alloc+init retain.
Now of course this is a contrived example because you'd probably really use:
self.myString = [NSString stringWithString: #"foo"];
which is a class method returning an autoreleased string and avoids the problem. But the idea is to show a simple example to explain this type of issue.
There are many other ways to not release memory properly, but the advice to work your way back up the call-chain until you get to your code is the way to go look at where you are triggering the allocation of the memory and then you can figure out why you aren't releasing that properly.
Try to do some issues in u code:
1. Please avoid hide declaration like
NSString *string = [dictionary valueForKey:[dictionary2 valueForKey:#"something"]]
Correct code is:
NSString *key = [dictionary2 valueForKey:#"something"];
NSString *string = [dictionary valueForKey:key];
key = nil;
Try to avoid declaration with autorelease and local declaration like:
NSArray *array = [NSArray array];
If u do this, make sure that u have:
NSArray *array = [NSArray array];
.... some code where array is using;
array = nil;
Better idea is alloc and release immediately when u don't need object and put it to nil.
3. Check if u using correct setters. Probably better idea is avoid to using it, at my experience, deallocate class start leaks for getters and setters, which was using before.
If u post some part of u code, where u seen most leaks (instruments give u possibility to click on leaked objects and see volume of leaks in programming code) community can suggest more.

memory leak when adding objects to nsarray

In the code below, PersonListArray is an NSMutableArray and I'm getting the list of persons from the sqlite DB and adding it to my array.
Person* tmpPerson = [[Person alloc] init];
tmpPerson.personName = #"Mike";
tmpPerson.personEmail = #"mike#mike.com";
[PersonListArray addObject:tmpPerson];
[tmpPerson release];
Even though I'm releasing the Person object here, its giving a memory leak which I'm guessing is due to the array holding a reference count to it. I'm using the array elsewhere in the program and then releasing it for sure.
What's the best practice to create new objects for an array and not run into this issue?
In the dealloc method where i release the array
-(void) dealloc{
[PersonListArray release]; // this contains the numerous Person objects
[super dealloc];
}
should i manually release them like this instead ?
-(void) dealloc{
for (int i = 0; i<PersonListArray.count;i++)
{
Person * tmpPerson = [PersonListArray objectAtIndex:i];
[tmpPerson release];
}
[PersonListArray release];
[super dealloc];
}
The code you are showing us is correct and contains no leaks. The last section is wrong, though, and would case your program to crash because you are releasing Person objects you no longer own.
Your code, as initially implemented, is correct. An array retains onjects added to it and releases them either when they're removed from the array or when the array is dealloced. No need to go through the array yourself.
What means are you using to detect the leak? If it's Instruments then you may be misunderstanding what it is telling you. When it detects a leak, it can show you where the memory was first allocated. It can't show you which object is responsible for the leak. I would therefore guess the given dealloc method is never called (because that object is leaked) or that someone else retains the array and doesn't release it. Try putting an NSLog in dealloc to ensure that it is occurring; as a run once test you could try logging PersonListArray after releasing it — if that doesn't cause a memory exception then almost certainly someone else has retained it.
[REMOVED: my original text "Try adding an NSLog of [PersonListArray retainCount] to your dealloc to figure out which is the case."; see comment from bbum below]
The most common cause of accidental additional retains is #property/#sythesize properties that are set to retain but for which a matching release is not added to dealloc.
Somewhere else in your app, you probably call [PersonListArray objectAtIndex:n] and pass it around to various other parts of your app. One of the other parts of your app is probably leaking it.
If you're using leaks, click on the particular "type of leak", then click on the memory address, and it'll show you the alloc/free/retain/release/autorelease history of that memory address. If you enable the detail view (Cmd-E I think), you'll see stack traces for all of those as well. Look for something that's doing a retain but not a corresponding release. (It's a bit difficult when things are retained by multiple autoreleased arrays...)

NSArray Memory Leak!! Not able to get Why?

Hi I am getting memory leak in Instruments for the following line of code .
NSArray *itemsList=[[NSArray alloc] initWithObjects:#"Love",
#"Hate",#"Happy",#"Sad",
#"Desire",#"Anger",#"Hope",#"Fear",#"Silly",nil];
I am using the below code:
arrayList is also released in dealloc block.
NSArray *itemsList=[[NSArray alloc] initWithObjects:#"Love",#"Hate",
#"Happy",#"Sad",#"Desire",
#"Anger",#"Hope",#"Fear",#"Silly",nil];
self.arrayList=itemsList;
[itemsList release];
I'm assuming that arrayList is declared using retain in the #property statement. If not, then that is certainly your problem.
If it is, then you have a leak, but not in the code you've posted. It's important to realize that Instruments first shows not necessarily where the leak occurred, but where the leaked memory was allocated. You'll have look through the rest of your uses of arrayList and find where you have a retain that's missing a release.
If you click on the arrow next to the memory address of the object in Instruments, you should be able to see everywhere that your object was retained and released. You'll have look through them and identify which retain is missing a release.

Why doesn't Instruments "Leak" template catch my memory leak on my iOS app?

I'm diving into iOS development and am getting familiar with the tools. At the end of every day, I perform a "Run with instruments tool -> Leaks" on my app to check for any memory leaks I may have implemented that day. It rarely seems to detect any leaks and, while I'd like to think I'm just a natural iOS programmer, I refuse to believe that ;)
Anyhow, I just found what I think is a memory leak in my code and it doesn't get caught by Instruments. I have this line of code...
gkSession = [[GKSession alloc] initWithSessionID:#"testID" displayName:#"Temp Display Name" sessionMode:GKSessionModeClient];
and I found that I wasn't calling release anywhere in my code. My questions are...
Is this a memory leak?
If so, what are some reasons that Instruments might not catch it?
My obvious concern is that I have memory leaks in my code and Instruments isn't catching them.
Thanks so much in advance for your help!
There are multiple types of dynamically allocated memory.
Memory with a reference count
greater than zero which is still referenced and is in use.
Memory with a reference count
of zero which is still referenced and is still in use.
Memory with a reference count greater than zero which is not referenced.
Memory with a reference count of zero which is not referenced.
Memory with a reference count
greater than zero which is still referenced and is NOT in use.
Type one is normal in use memory. Type two is a bug that will be reported as an illegal access when you try to follow the reference. Type 3 is the type of leak that instruments detects. Type 4 should be freed by the memory system.
Type 5 is a leak which cannot be detected by instruments, and will also not be handled by a full garbage collector. This is what you seem to have.
EDIT:
I forgot type 6 -- Memory with a reference count that doesn't match the number of actual references. This will probably eventually turn into type 2 or 4.
The answer to #1 is "maybe"... if your view controller gets popped off the stack, and no one else has retained it, then your view controller should get deallocated. But, (and this may be the answer to your question #2) one of the mistakes I made originally was not understanding that when you call pushViewController: the navigation controller will retain your view controller, so you don't have to. Make sure you are releasing your view controller after you create it and push it on the stack.
MyViewController * viewController = [[MyViewController alloc] init...];
[self.navigationController pushViewController:viewController];
[viewController release];
I believe the static analyzer will warn you if you forget the release call in this situation... which is one reason the static analyzer is so great.
If you don't release the view controller at this point, your retain count will always be +1 higher than it should.
I've noticed the static analyzer is MUCH more useful for these things than the instruments' leak tool. (Which, for example, won't find a "leak" that includes circular references... two leaked objects that reference themselves don't show up because "a reference" is still around for your object).
So currently you have something along the lines of...
#interface MyClass : UIViewController
{
GKSession * gkSession;
}
...
#end
in your implementation you should make sure you release your iVar in your dealloc method:
#implementation MyClass
...
- (void)dealloc
{
[super dealloc];
if (gkSession) [gkSession release];
}
#end