I allocated an object like this:
PixelInfo *ob1=[[PixelInfo alloc]initWithName:clr :t];
Then the retaincount of object is 1.
Then I did like this....
[faceColor addObject:ob1];
Then the retain count increased to 2. Why?
for(b=xi[i];b<=(xi[i+1]+1);b++)
{
CGPoint t;
t.x=b;
t.y=y;
UIColor *clr=nil;
clr=[self getPixelColorAtLocation:loadImage.CGImage :t];
PixelInfo *ob=[[PixelInfo alloc]initWithName:clr :t];
[faceColor addObject:ob];
[ob release];
}
This is my code .Even after releasing the object ob,Memory leakage happens.Why?
All colllections (Array, Dictionary, Set) increase object's retain count when you doing
[smth addObject: obj].
PS. AddSubview also increase retain count of subview
I assume faceColor is an NSMutableArray. When you add an object to a container like NSArray or NSDictionary, the container retains the added object. That's because the container now relies on the added object to continue to exist as long as it is inside the container.
In below statement,you have alloced the object then retain count will be increased by 1 that's why you are getting is 1.
PixelInfo *ob1=[[PixelInfo alloc]initWithName:clr :t];
In next statement,I consider faceColor is an NSMutableArray
[faceColor addObject:ob1];
You are adding the object ob1 in an array, So iOS will increase the retain count of any object by 1 if you add that in an Array,
That's the reason,You have retain count 2.
EDITED:
Here is what apple says.
Important: This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
Related
In the following code snippet:
NSMutableArray *tmpItemsArray =[[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(fetch_statement)==SQLITE_ROW){
int pk = sqlite3_column_int(fetch_statement,0);
Item_A *itemA = [[Item_A alloc] getItemA:pk fromDatabase:db];
// calculate and set a property of itemA
[itemA setValue:xValue forkey:xKey];
// insert into array
[tmpItemsArray addObject:itemA];
[itemA release];
}
sqlite3_reset(fetch_statement);
// for each ItemA in array
// update itemA in database
for (Item_A *eachItemA in tmpItemsArray) {
[eachItemA updateItemAInDatabase:db];
}
When I add object to tmpItemsArray using addObject: method, the object at memory address pointed by itemA is added to the array. In other words, an object in tmpItemsArray is pointing to the same memory address as is pointed by ItemA.
Now when [itemA release] is executed, to release the memory -
would tmpItemsArray have objects pointing to invalid memory
or
does [itemA release] only releases the hold(in a way) itemA has over this memory?
release doesn't actually cause memory to be freed. Instead it decrements a count that represents how many times some part of the code has retained the object. The act of allocating the object is equivalent to one retain and adding it to the array is another. Your release balances the alloc and, at that point, the array's retain is keeping it from being deallocated.
When the array goes away, barring other events, it will release its contents. Since it's an autoreleased array, that's likely to happen on the next iteration of the program's event loop.
No, when [itemA release] is called, a counter decrements and the memory is released only when the counter reaches zero. Each time someone claims ownership of the object (for instance when entered into an array), the counter increments.
I have this method which leaks ~ 6KB :
+ (EInspectorFacilityInfo*) newWithNode: (CXMLNode*) node
{
if(node == nil) { return nil; }
return (EInspectorFacilityInfo*)[[[EInspectorFacilityInfo alloc] initWithNode: node] autorelease];
}
here is a screenshot indicating the memory leak in instruments.
how can I get rid of this memory leak ?
The method has the word 'new' in it, so by the Objective-C conventions it is expected to return an owning reference to the object, ie. an object with a retain count of 1. Auto releasing the object returns an object with a retain count of 0.
You must either remove the word new from the method name, or not auto release the object - in which case, the caller will be responsible for releasing it.
Small addition to Jasarien answer, you should name your method something like:
+ (EInspectorFacilityInfo*) inspectorFacilityInfoWithNode: (CXMLNode*) node
This would fix your problem and match Cocoa coding style and spirit.
i've a Class method like this:
+(CCScene *) sceneWithMovie:(NSString*)movieName level:(NSString*)levelName hudLevel:(NSString*)hudName
{
bbsScene* scene = (bbsScene*)[super sceneWithMovie:movieName level:levelName];
ScenePage* hudLayer = (ScenePage*)scene.layer;
UTLOG(#"---> %p RETAIN COUNT: %d",hudLayer.hudLoader,[hudLayer.hudLoader retainCount]);
TouchLevelHelperLoader* loader = [[TouchLevelHelperLoader alloc]initWithContentOfFile:hudName];
hudLayer.hudLoader = loader;
UTLOG(#"---> %p RETAIN COUNT: %d",hudLayer.hudLoader,[hudLayer.hudLoader retainCount]);
[loader release];
UTLOG(#"---> %p RETAIN COUNT: %d",hudLayer.hudLoader,[hudLayer.hudLoader retainCount]);
[hudLayer.hudLoader addSpritesToLayer:hudLayer];
NSInteger sceneNumber = [[[[self class]description] stringByReplacingOccurrencesOfString:#"Scene" withString:#""]intValue];
[hudLayer loadTextPage:sceneNumber fromFile:SCENE_TEXT_FILE];
// return the scene
return scene;
}
The output is:
2011-09-22 10:53:28.477 MP NO VID[598:207] ---> 0x0 RETAIN COUNT: 0
2011-09-22 10:53:28.490 MP NO VID[598:207] ---> 0x64af820 RETAIN COUNT: 2
2011-09-22 10:53:28.491 MP NO VID[598:207] ---> 0x64af820 RETAIN COUNT: 2
When i release loader the data is lost as if i don't call hudLayer.hudLoader = loader;
Obviously i set:
#property(nonatomic,retain)TouchLevelHelperLoader* hudLoader;
Any ideas? Maybe the class mothod (+) is the problem?
You shouldn't rely on the retainCount property.
It is not very reliable because you never know what is done behind the scene.
For example when using Class Clusters like NSString, there are so many things that are done internally in the NSString class that retainCount can't have a real meaning for you. For some cases like NSTimers & so on, objets are also released by the RunLoop (when scheduled on this runloop) but if you don't know it, it is not trivial...
Obviously these two examples (class clusters and runloop retention) are not what you are having here, but what I'm saying here is that the retainCount property is not something that you should rely on to check if you have a leak.
Moreover, if you have the Garbage Collector activated for your project, release is a NO-OP (because that's the GC itself that will manage and release the instance)
Actually, the use of retainCount is prohibited since Xcode4 when you use ARC in your project.
To check if you have leaks in your code, use the Static Analyser ("Build & Analyse" from Xcode Build menu) and/or Instruments "Leaks" tool.
This piece of codes segment fault on me, any idea why? allButtons is a NSMutableArray, it contains 3 objects, a=0, b=1, a and b are int type
if(a != -1 && b!= -1){
//Swap index in "allButtons"
id tempA = [allButtons objectAtIndex:a];
id tempB = [allButtons objectAtIndex:b];
[allButtons replaceObjectAtIndex:a withObject:tempB]; //Seg fault here?????
[allButtons replaceObjectAtIndex:b withObject:tempA];
needLoad = false;
[self setUpButtons];
}
EDIT:
NSMutableArray *allButtons = //fetch the array from Coredata. This work since I display the data onto the screen, plus, [allButtons count] return 3, and a=0, b=1
f(a != -1 && b!= -1){
//Swap index in "allButtons"
[allButtons exchangeObjectAtIndex:a withObjectAtIndex:b];
needLoad = false;
[self setUpButtons];
}
The first call to replaceObjectAtIndex: will release the old object (tempA), but that shouldn't cause a seg fault. As #Zoran mentioned try logging the retainCount for tempA and verify its count.
Also for swapping elements in an array, you should use exchangeObjectAtIndex:withObjectAtIndex instead of replaceObjectAtIndex:withObject. It's supported from iPhone 2.0.
Just because you have said
NSMutableArray *allbuttons = // something
doesn't mean that it is definitely an NSMutableArray, it just means that the compiler thinks that it will be a NSMutableArray.
If it's from CoreData, it's probably just an NSArray so the method calls you are trying won't work - you'll get unrecongnised selector or something like that.
You will have to convert it to a mutable array first
NSArray *coreData = // core data call
// Create a mutable copy
// NB This means that you are now working on a copy, not the original :)
NSMutableArray *allButtons = [coreData mutableCopy];
tempA is going to be released when you call the first replaceObjectAtIndex. Keep that in mind when calling this... I have no idea why releasing tempA would seg fault for you, examine what its dealloc does perhaps.
Check the retain count of tempA to verify that it is indeed dealloc-ed (not simply released) by the call to replaceObjectAtIndex like so:
id tempA = [allButtons objectAtIndex:a];
NSLog(#"retain count for tempA: %i", [tempA retainCount]);
If you see a retain count of 1 at this level, then your object tempA is being dealloc-ed by the call to replaceObjectAtIndex
Please read and understand the Cocoa rules on object ownership. Note that you have not claimed ownership over the objects referenced by tempA and tempB and you must therefore heed the following:
A received object is normally guaranteed to remain valid within the method it was received in ... (although you must also take care if you modify an object from which you received another object). That method may also safely return the object to its invoker.
Basically, the line:
[allButtons replaceObjectAtIndex:a withObject:tempB];
May cause tempA to be deallocated. This means that the subsequent line will cause allButtons to send a retain message to an invalid object, hence the seg fault. To fix the problem, you need to retain tempA before the swap and release it or autorelease it after.
NB it's wise to forget about retain counts. Unless you are fully aware of the implementation of all objects that touch your objects, you cannot make any assumptions about what the retain count of an object is. For instance, there's no rule that says that the implementation of NSMutableArray will only ever retain its elements once.
Use this method pass the appropritate index
exchangeObjectAtIndex:withObjectAtIndex:
Given the next code snippet:
...
- (void) setTotalAmount: (NSNumber*)input
{
[totalAmount autorelease];
totalAmount = [input retain];
}
- (void) dealloc
{
[totalAmount release];
[super dealloc];
}
...
What I want to understand how really we set value.
We allocate local (instance) var and "retain" to input var. But what is "input"? Is it a pointer to real value? Or is it value itself?
When we "retain" do we get a pointer to "input" or pointer to value or just the value?
And pretty same questions with dealloc and release. What actually "dies" here?
Thank you!
It's clear that input is a pointer. You have declared its type in the argument list as NSNumber*.
input is a pointer to an object of type NSNumber. Internally, the object has an integer variable that holds the number of external references to it. Sending the retain message to an object will increment its reference count. Sending the release message will decrement the count. Sending the autorelease message will adds the object to the local autorelease pool which will keep track of autoreleased objects and sends the release message to them next time it drains. An object with reference count of 1 that receives a release message will get deallocated and its dealloc method will get called. You should release all the resources you hold when you are deallocated.
When you are setting a property, you want to release the old value and make sure the new value is kept around as long as the object itself is alive. To make sure the new value is kept around, you increment its reference count by 1 by sending it the retain message. To release the old object, you'll send it the release message. There's one subtle issue here. If the old value is the same as the new value, if you release the old value first and its retain count was 1, it'll get destroyed before you can increment it. That's why you should retain the new value before releasing the old one.
Assuming that you have instantiated an object of the above class named "myObject", you could set its totalAmount like this:
...
// get a new NSNumber object which will be autoreleased
NSNumber *amount = [NSNumber numberWithInteger:10];
// call the setter which will autorelease the previous value of
// totalAmount (if any), retain the object referenced by "amount"
// (so that object will no longer be deallocated when it's autoreleased),
// and reference that object from the totalAmount instance variable
myObject.totalAmount = amount;
...
Later, when "myObject" is deallocated, the object referenced by the totalAmount instance variable will be released (and deallocated if it was not retained anywhere else).
input is the NSNumber
- (void) setTotalAmount: (NSNumber*)**input**
Which is called by doing something like this:
[object setTotalAmount:number];