Hey guys, suppose the following code:
int main (int argc, const char * argv[])
{
//[...]
Rectangle* myRect = [[Rectangle alloc] init];
Vector2* newOrigin = [[[Vector2 alloc] init] autorelease]; // ref count 1
[newOrigin setX: 50.0f];
[myRect setOrigin: newOrigin]; // ref count 2
[myRect.origin setXY: 25.0f :100.0f]; // ref count goes to 3... why ?
[myRect release];
[pool drain];
return 0;
}
Rectangle's origin is declared as a (retain) synthesized property.
Just wondering 2 things:
Why does ref count goes to 3 when using the getter accessor of Rectangle's origin? Am I doing something wrong ?
With a ref count of 3, I don't understand how this snippet of code cannot leak. Calling release on myRect will make it go down to 2 since I call release on the origin in dealloc(). But then, when does autorelease take effect?
Thanks!
Why does ref count goes to 3 when
using the getter accessor of
Rectangle's origin?
Because your #property is declared as atomic (the default) and, thus, the synthesized getter retains and then autoreleases the return value.
Am I doing something wrong ?
Yes. You are studying absolute retain counts.
The absolute retain counts of any object is quite thoroughly useless to consider. You only care about deltas; if you cause the retain count to increase, you must cause it to decrease.
With a ref count of 3, I don't
understand how this snippet of code
cannot leak. Calling release on myRect
will make it go down to 2 since I call
release on the origin in dealloc().
But then, when does autorelease take
effect?
An autorelease is simply a delayed release that kicks in when the containing pool is drained. So, in your case, the object will be deallocated when [pool drain]; is executed.
From Apple's documentation on -retainCount:
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
Im doing some research on blocks,
the code here
typedef NSString* (^MyBlock)(void);
#property(copy,nonatomic) MyBlock block1;
in viewdidload
self.block1 = ^{
self
NSLog(#"do block");
return #"a";
};
of course the self is retained, then I do a
self.block = nil;
by checking the retain count of self, I found it reduced by 1, no retain cycle.
I believe this is the correct situation, the block retains self, when release the block, self gets released. retaincount reduced.
I made a litte change, and things coms strange:
make block a local variable.
in viewdidload
MyBlock block1 = ^{
self
NSLog(#"do block");
return #"a";
};
[block copy]; // retain count of self gets added.
[block release]; // retain count of sell still the same
why? I tried Block_release(), its the same. and when putting a local variable like NSArray in the block, the retain count fellows the same rule as self.
there must be some thing different inside of #property, anyone researched this before?
pls help.
Additionally, I do this in ARC, a local variable block will made the retain cycle, and a instance variable didnt, due to the autorelease, it holds the self, and few seconds later, it released and self object get released normally.
is it because the instance variable and local variable are alloc on different parts in memory? stack ? heap?, are they both copied to heap when do a [block copy]?
EDIT :
not instance variable and local variable. using #property makes it different, any explanations?
The problem is that using retainCount to figure out things like this is futile. The retainCount will not reflect autorelease state and the compiler -- the ARC compiler, in particular -- may generate different code (in particular, the optimizer has a tendency to eliminate unnecessary retain/autorelease pairs).
Use the Allocations Instrument and turn on reference event tracking. Then you can look at each retain/release event on the object, the exact stack trace where it happened, and know exactly what is going on.
Under non-ARC, when you assign to an iVar, nothing happens. When you go through the setter, a retain setter will cause the object to be retaind. Under ARC, a block will be copied to the heap automatically in a number of cases, triggering a retain of the captured object when the block is copied.
http://www.whentouseretaincount.com/
MyBlock getBlocks()
{
MyBlock myBlock = ^{
NSLog(#"Hello World!");
};
return myBlock;
}
int main(int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MyBlock myBlock = getBlocks();
myBlock();
[pool drain];
return 0;
}
Why does this snippet of code work? myBlock should be destroyed.
By the way, this snippet also works:
NSObject *obj = [[NSObject alloc] init];
NSLog(#"%ld", [obj retainCount]);
MyBlock myBlock = ^{
NSLog(#"Hello World!");
NSLog(#"%ld", [obj retainCount]);
};
[obj release];
but [obj retainCount] in block prints 1 instead 2, why?
Blocks can be allocated on the stack for performance reasons and only migrate away to the heap when you copy them. If your block doesn't capture any values, the compiler can also turn it into a global block whose memory exists in some fixed static memory location.
Since your getBlocks block doesn't capture anything, it is a global block and its memory can't be disposed. It doesn't have reference counting semantics and retain/release won't do anything. Its reference will always be valid and you'll always be able to call it.
If the block in getBlocks did capture some values, it would be a local stack-allocated block, and the method would be returning a reference to that stack memory, which is of course very dangerous. The code may even still work in this case and you'd be able to call it even though it is sitting in unowned stack memory (as long as that memory hasn't been trashed by somebody else by the time you call the block).
I believe your second example is also demonstrating the side effects of a stack-allocated block. The objects captured by a stack-allocated block will only be retained when the block is actually copied to the heap for the first time. This doesn't happen in your code so obj isn't retained by the block.
This does mean that after calling [obj release] in your example, the block is now capturing a dangling pointer. Using ARC will fix all these messy details for you.
See How blocks are implemented (and the consequences) (Cocoa With Love) for more details.
Edit: Also, obligatory link to when to use retainCount
Why does this snippet of code work?
The first snipped is working because the block implementation has no reference to the surrounding scope, and it's therefore configured by clang as a global block. This causes the block not to be on the stack as it would normally be.
myBlock should be destroyed.
Stack frames (and their local variable) don't get destroyed. Their memory is made available for further allocation. Anyway, due to the simplicity of your example, you're getting a global block which doesn't live on the stack frame.
If you were making any reference to the surrounding scope you would have had a stack-based block and myBlock would have been a dangling pointer to an on-owned memory location, likely leading to a crash.
[obj retainCount] in block prints 1 instead 2, why?
Sounds reasonable.
You are allocating an object (retain count: 1), the block is retaining it (retain count: 2), you are releasing it (retain count: 1), the block is eventually executed (retain count still 1).
As a general note, anyway, don't rely upon retainCount when reasoning about memory. The memory management process has a lot going on under the hood, and you cannot definitely say anything only by looking at the value of retainCount, due to internal details of the implementation that you cannot possibly take into account. More on the subject here: http://whentouseretaincount.com/
I have a custom class called Hexagon which is a subclass from NSObject. However when I assign it to a sprite and add it to the screen by calling -addChild:, it has a retain count of 2! What should I do, in order to stop that leakage ?
for (int i =0; i < HEXCOUNT; i++){
Hexagon *nHex = [[Hexagon alloc]initWithDicitonary:hexPositions];
CCSprite *theSprite = (CCSprite*)nHex;
NSString *hexName = [NSString stringWithFormat:#"hexagon%d", i];
CGPoint location = CGPointFromString([[EXHEXAGONS objectForKey:hexName]objectForKey:#"position"]);
CGPoint nLocation = ccp(screenSize.width/2 + 68 * location.x,screenSize.height/2 + 39 * location.y);
theSprite.position = nLocation;
[self addChild:theSprite z:1 tag:i];
NSMutableDictionary *hexProperties = [EXHEXAGONS objectForKey:hexName];
[hexProperties setObject:theSprite forKey:#"realSprite"];
[EXHEXAGONS setObject:hexProperties forKey:hexName] ;
[[GameStateSingleton sharedMySingleton]setExistingHexagons:EXHEXAGONS];
[nHex release];
}
Don't rely on retainCount for anything. A retainCount of 2 doesn't mean the object is leaking. Only Instruments can tell you that.
Creating the Hexagon object with alloc/init will add a retain count of +1. Adding it as child will add +1. So depending on where you log the retainCount, it may be correct.
If you worry about memory leaks, by all means start using ARC.
First off, worrying about retain counts is not productive unless you are verifying that it is not getting deallocated when fully released from all the various objects which retain it.
Secondly, presumably you are putting the object into a NSArray, NSSet, or NSDictionary within addChild:z:tag:? So, that would bump it's retain count up by one.
You also cast your Hexagon object to a CCSprite and add it to the NSDictionary hexProperties, which will add another 1 to your retain count.
By the time you release your object at the bottom of the loop, your retain count will be at least 3. After the release it should be at least 2.
I have read that dealloc for an object will be called, only if retain count of that object becomes zero.
I am taking one object for UIColor in interface section and setting property
UIColor *currentColor;
#property (nonatomic, retain) UIColor *currentColor;
After using this object in the implemetation section, I am calling release method for this object in dealloc
-(void)dealloc
{
[currentColor release];
[super dealloc];
}
I am in doubt how dealloc will be called for this object, because I am not releasing the retained object anywhere. Thanks in advance.
I have read that dealloc for an object will be called, only if retain
count of that object becomes zero.
Yes.
For the sake of simplicity, call the class that contains currentColor object as ColorContainer. Now, if you create an instance of ColorContainer like the following:
ColorContainer* containerColor = [[ColorContainer alloc] init]; // retain count + 1
the retain count for containerColor becomes 1.
Suppose you create an instance of a UIColor and you set that instance to currentColor property. In this case you can follow two different ways.
In the first one you can create an instance like the following. If you use an instance method like initWithRed:green:blue:alpha: you have to release memory explicitly.
UIColor color* = [[UIColor alloc] initWithRed:0 green:0 blue:0 alpha:1]; // retain count + 1
containerColor.currentColor = color; // retain count +1, the referenced object has a retain count of 2 because you use a retain policy
[color release]; // retain count -1, now the referenced object has a retain count of 1
In the second way, instead, you could use a class method (+ symbol). In this case you don't need to release memory explicity because the object created in that class method will be autoreleased at a certain point of your application lifetime.
containerColor.currentColor = [UIColor whiteColor]; // retain count +1
Now suppose you release containerColor object. If the retain count for containerColor is equal to 1, releasing it from an object that uses it, it enables to call its dealloc method and, in consequence, to dismiss also the object referenced by currentColor.
In this simple case study you have to note that the object referenced by currentColor is completely removed from memory (dismissed) only if it has a retain count of 1. In fact, if you do this
UIColor color* = [[UIColor alloc] initWithRed:0 green:0 blue:0 alpha:1]; // retain count + 1
containerColor.currentColor = color; // retain count +1, the referenced object has a retain count of 2
//[color release];
you create a memory leak (Do you understand way?).
To summarize, when you use retain, copy, init or new (it's the same of alloc-init), you have always to call their counterparts release or autorelease.
As a rule of thumb, you need always to balance the retain count for objects to avoid memory leaks.
So, as a methaphor you could think to memory like a tree. Suppose you have a parent (containerColor) and a child (currentColor). If the parent (with a retain of count of 1) is released, it causes to call its dealloc method and free memory for its object. If in its dealloc method you release a child (with a retain count of 1) it causes to call its dealloc method and free memory. In the case a child has a retain count greater than one, you cause a memory leak.
Hope it helps.
Edit
For further information you could read About Memory Management. Since iOS 5 Apple has introduced ARC. Automatic Reference Counting is a compiler machanism that provides automatic memory management of Objective-C objects. For info see Transitioning to ARC Release Notes.
When you use retain setter for currentColor property you retain that object, and if you retain , copy or alloc memory for a object you MUST RELEASE IT. -(void)dealloc is the best place to do it
You should only call release on the object if you allocated it (via alloc, copy or retain). Properties with the retain attribute will automatically do the memory management for you as long as you handle them properly, e.g. only access them via self.currentColor. Depending on how you created the color object you might or might not use release but you always should set the property to nil in your dealloc method. Two examples:
// If you use this (or some other way to get the color without alloc, copy or retain)
// then you do not need to do any release
self.currentColor = UIColor.blackColor;
self.currentColor = [UIColor colorWithRed:1.0 green:0.5 blue:0.2 alpha:1.0];
// On the other hand if you get it like this, you have to release/autorelease the object
self.currentColor = [[UIColor alloc] initWithRed:1.0 green:0.5 blue:0.2 alpha:1.0];
[self.currentColor release];
// or better
self.currentColor = [[[UIColor alloc] initWithRed:1.0 green:0.5 blue:0.2 alpha:1.0] autorelease];
// dealloc always the same
-(void)dealloc{
[currentColor release], currentColor = nil;
[super dealloc];
}
There are two important facts here:
For each alloc, copy or retain that your code issues, you have to issue release or autorelease.
Always use self.currentColor to access the property and not currentColor except when deallocating. The thing here is that when using self.currentColor the system automatically adds memory management code. Whenever self.currentColor is set, it automatically retains and releases the objects. Only on final deallocation you should set the variable directly, for more information see this answer on the topic (thanks to Flex_Addicted).
I am trying to get the hang of retain / release. I get that they are a matched set. But I don't know when I have to retain references.
-(void)sampleMethod:(RandomClass *) obj {
[obj retain];
// Do stuff to object...
[obj release];
}
Is it necessary to retain (and thus release) obj?
I am worried about obj going away. Does it follow that you must (if) retain reference parameters as soon as possible in the function? What about the space of time between the functions call and the first instruction of the function?
Thanks!
Short answer; use ARC.
Joe's answer is more or less correct. Until it isn't.
In general, there is no need to retain arguments or return values from other methods. However, the resulting code only works by coincidence and convention, not by algorithmic analysis.
Consider:
NSString *foo = [aMutableArray objectAtIndex: 5];
[aMutableArray removeObjectAtindex: 5];
[someTextField setTextValue: foo];
BOOM!
Your code just crashed. Maybe (it won't crash if foo happens to be a constant string or happens to have been retained by something else or happens to have been retain/autoreleased somewhere else).
Technically, that should be:
NSString *foo = [aMutableArray objectAtIndex: 5];
[foo retain];
[aMutableArray removeObjectAtindex: 5];
[someTextField setTextValue: foo];
[foo release];
That is, foo should be retained the moment it comes into scope and released the moment it is no longer used in a scope. Or you could [[foo retain] autorelease];, but autorelease pressure can be a problem (it generally isn't, but it can be).
ARC does this kind of analysis and would ensure that foo is retained as shown above when necessary.
You do not have to worry about the object being passed going away so there is no need to retain it. Proper memory management* ensures that the object will live for the duration of your method because it will be within the same thread as the caller, therefore the autorelease pool for that thread should not be drained and the caller can not release the object until your method has returned. This even holds true with methods such as performSelectorInBackground because that will retain the argument.
*Proper memory management - This means each thread that uses auto released objects gets it own autorelease pool that is drained within the same context it is created and objects passed across threads are properly retained.