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...)
Related
When running Analyzer, I receive the "Object sent -autorelease too many times" warning. I know I'm doing something tricky (and am open to alternatives to accomplishing my goal).
Essentially, I wanted to keep a stack of specific types of controllers handy for sending messages from a central location. So, considering:
From 'ActionBroker' shared object:
NSMutableSet *liveActions;
liveActions = [NSMutableSet alloc] init];
...
CLViewController *action = [[[actionClass alloc] init] autorelease];
if (!action) {
return nil;
}
[self.liveActions addObject: action];
// When adding an object, the retain count is increased. We want the action
// to dealloc, so that it might remove itself from the list...
[action release];
return action;
And the complementary dealloc code:
[[CLActionBroker sharedActionBroker] removeAction: self];
[super dealloc];
... and in removeAction:
[action retain];
[self.liveActions removeObject:action];
The above code works, I just get the nagging error. And the nagging sensation that I could probably solve the problem a different way.
One of the use cases for this code is to pass an 'handleOpenURL' request through a chain of open controllers and returning the first 'YES' response.
As I understand it, your intent is to have a set of controllers ("actions") in the set, which you could easily access from anywhere in your app. If one of these controllers is deallocated, it would automatically remove itself from the set.
There's a problem with this setup, though. As you've described it above, the controller is supposed to be removed from the liveActions set upon deallocation. But since an NSSet retains its members, your controller will never be deallocated so long as it is still in the liveActions set. -dealloc is only run when all retains have been balanced by a release.
This, then leads to your over-release, which leads to the warning. Since you've sent an extra release, -dealloc could be run while the controller is still in the liveActions set. But when you remove it from that set, it's going to send a release message to your object, which would take its retain count negative. That may or may not be safe, but in either case it's an ugly workaround.
What you really want, it seems, is a set that does not retain its members. This is normally a dangerous configuration, since it can lead to dangling pointers in the set. But if you're willing to manage the lifetime of the object and clear out those dangling pointers at the appropriate times, it turns out that it's quite doable. You just need to use a CFMutableSet instead of an NSMutableSet. And since the two are toll-free bridged, it doesn't even add that much complexity.
Setting up the CFMutableSet looks like this:
// The NULL for the third parameter tells the set to not do anything when
// an object is added to or removed from the set.
CFMutableSetRef cfLiveActions = CFSetCreateMutable(NULL, 0, NULL);
// Toll-free bridging makes this possible
NSMutableSet *liveActions = (NSMutableSet *)cfLiveActions;
After that, you can use it exactly as you would use any other NSMutableSet; this one will just be special in that it won't retain its members.
The problem:
CLViewController *action = [[[actionClass alloc] init] autorelease]; // +0 ownership
// ...
[self.liveActions addObject: action]; // liveActions takes ownership
// ...
[action release]; // -1 ownership
When you've alloced the object, you are responsible for it. But then when you autorelease it, you've fulfilled your obligation (and because you autoreleased instead of releasing, you can still use the object until the next turn of the runloop). You shouldn't release it again later.
Also:
[action retain];
[self.liveActions removeObject:action];
The retain is unnecessary.
(And here's another plug for beginning to switch to ARC, under which you won't have to worry about this!)
[Edit: misunderstood your question. Revised answer forthcoming.]
[Edit 2: never mind... even though I misread your intent, I believe my solution is still right.]
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.
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.
What's the right way to do this?
I have an array that I will use on several methods. I will add objects to it, get values, replace values, etc.
Today I do this:
I declare it on .h, using something like
NSMutableArray *myArray;
as soon as the application starts, I declare it on .m doing something like
myArray = [[[NSArray alloc] init] retain];
If I don't add the retain the array will be released at some point and the application will crash. But allocating the array at the beginning of the application and left it "open" without releasing it will make instruments cry, pointing the finger at me, calling me a "leaker"...
How to solve that? Is this the correct way to do that? how do you guys do stuff like this?
thanks
alloc implicitly sets the retain count to 1. By sending the retain message you're incrementing the retain count to 2. In order for the object to be deallocated you would then need to release it twice. Failure to do so would result in a memory leak.
Ideally you should create the object in your init method using [[NSArray alloc] init] and then release it in your dealloc method like so:
- (void)dealloc {
[myArray release];
[super dealloc];
}
You might also find this article useful: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
One more thing: You declared myArray as an NSMutableArray but instantiated it as an NSArray. Perhaps that's causing the crash.
You should not retain the object you've just created. You already own it. If, as you say, "the array will be released at some point and the application will crash," that is the code you should change. Your code shouldn't be releasing an object that you still want to keep around.
Wondering if someone with experience could possibly explain this a bit more. I have seen examples of...
[view release];
view = nil;
....inside the (void) dealloc.
What is the difference and is one better then the other?
What is the best way?
When doing retainCount testing I have personally seen nil drop a count from 3 to 0 for me, but release only drops it from 3 to 2.
What you have seen is probably these:
1) [foo release];
2) self.bar = nil;
3) baz = nil;
Is releasing the object, accessing it through the instance variable foo. The instance variable will become a dangling pointer. This is the preferred method in dealloc.
Is assigning nil to a property bar on self, that will in practice release whatever the property is currently retaining. Do this if you have a custom setter for the property, that is supposed to cleanup more than just the instance variable backing the property.
Will overwrite the pointer baz referencing the object with nil, but not release the object. The result is a memory leak. Never do this.
If you are not using properties (where self.property = nil will also release an object) then you should ALWAYS follow a release by code that sets the reference to nil, as you outlined:
[view release]; view = nil;
The reason is that it avoids he possibility that a reference can be used that is invalid. It's rare and hard to have happen, but it can occur.
This is even more important in viewDidUnload, if you are freeing IBOutlets - that's a more realistic scenario where a reference might go bad because of memory warnings unloading a view, and then some other code in the view trying to make use of a reference before the view is reloaded.
Basically it's just good practice and it will save you a crash at some point if you make it a habit to do this.
#bbullis22 you have seen the restain count drop from 3 to 0 because you set the reference to nil. then you asked for the retaincount of 'nil' which is zero. however, the object that used to be referenced has the same retain count - 1 (due to setting the reference to nil).
using release, the reference still references the same object, so that's why you see the retain count drop from 3 to 2 in this situation.
As far as usage inside your code, in your dealloc you don't need the assignment to the property, releasing is all you need to do.
- (void)dealloc {
[myProperty release]; // don't need to assign since you won't have the object soon anyway
[super dealloc];
}
I think using both is kind of safety net. With only release in place you could run in problem if you screwed reference counting management. You would release an object, giving its memory back to system but pointer would be still valid.
With nil you are guaranteed that program will not crash since sending message to nil does nothing.