NSArray Memory Leak!! Not able to get Why? - iphone

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.

Related

EXEC_BAD_ACCESS when i try to release a NSString that has an address allocated to it

I have a NSString that i try to release.
The problem is that in some cases i get EXC_BAD_ACCESS when i try to release it. The NSString has a address allocated to it (I can see in the bottom page that it has allocated memory at 0xABCDEF).
How can avoid this problem while realeasing when there is something there ?
You can release an object, but the pointer to it can still have a value. It's just that it's a garbage value (i.e. a dangling pointer).
That's why you see a lot of code such as:
[myObject release];
myObject nil;
which first releases the object and then sets the pointer to nil. That way any message sent to it will fail silently (because it's safe to send messages to nil objects in Objective-C) rather than crashing, as seems to be happening with your app.
Since you are checking the pointer, I suspect that you are doing something weird with memory management. Don't. Just follow the Memory Management Rules and only release the objects you own.
You've likely called [release] on an already released string. How are you allocating it? When an object is released, or autoreleased, it is not automatically set to nil (0x0).
[[NSString alloc] initWithSomething] requires a release call.
[NSString stringWithSomething] does not, as by convention, it is autoreleased.

iPhone object checking to release

I want to check if an object has some count or not Here is my testing code
NSMutableArray *array=[[NSMutableArray alloc]init];
if(array)
{
NSLog(#"hiiiiiii");
}
CASE-2
NSMutableArray *array=[[NSMutableArray alloc]init];
[array release];
if(array)
{
NSLog(#"hiiiiiii");
}
Here in both cases i got same output as printed "hiiiiiii".
Can anyone tell me how will i check if my object need to release or already released.
I know that i should have track of my object's counters but i am at a stage where my code is too much complexed and i need help..
Please help..
ALso tell that how much memory leak is allowed by apple?
There is no way to check if you "should" release an object. Doing something like "if(object)" only checks the pointer to the object. It will return true even if the object it was pointing to was destroyed a long time ago. This is what happens in your second case. The object is destroyed when you call release, but the pointer is still pointing at something, so it returns true. It will only return false if the pointer is set to nil.
However, there is a simple set of rules for calling release. If you ever call "alloc", "new", "copy", "mutableCopy" or "retain" on object, you must always call "release" or "autorelease" on it. That will prevent any memory leaks.
Apple does not have a publicized amount of memory leaks allowed. It is always safest to eliminate any known memory leaks; plus, it will mean better performance for your customers.
In your second case you are releasing the NSMutableArray but still it store a non zero value although it's no longer for use (To call function OR fetch value).That the reason your if condition got true.
Just remember whenever you call release on any object, Do'nt forget to assign nil to that, So your second code should look like below.
CASE-2
NSMutableArray *array=[[NSMutableArray alloc]init];
[array release];
array = nil;
if(array)
{
NSLog(#"hiiiiiii");
}
There is a simple rule of memory management in Object-C if your alloced or retain any object you must call release on that,
Read memory management Guide from Apple.

why is there a memory leak in the SimpleEKDemo code?

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.

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...)