I recently came across this blog post where two flavors of instance variable deallocation are discussed. To give you a summary:
The first approach
- (void)dealloc {
[instanceVar release];
[super dealloc];
}
is considered to leave a pointer alive until the method returns. This can lead to undefined behavior.
The second approach
- (void)dealloc {
[instanceVar release], instanceVar = nil;
[super dealloc];
}
is considered to be more stable for production code because the instaceVar is set to nil.
OK. Here is the question you've been waiting for:
Are both solutions the same? Or does the comma separation of expressions make them atomic?
The blog post you link to is from 2010.
The more interesting point nowadays is that you have to do neither. If you use ARC, then you can't send a release message to objects.
The setting of nil after release was to prevent non-retained objects to be sent messages after they were deallocated and cause a crash. I say non-retained objects, because if they were retained objects, they wouldn't (shouldn't) be released unknowingly. Again, with ARC (as long as you aren't using ARC-lite) you can mark non-retained objects as weak, and weak pointers auto-zero; i.e. when the object they point to is deallocated, the pointer is set to nil.
So the second case, with pointers being set to nil after a dealloc, is considered safer at run-time, but you don't have to worry about it now, as ARC handles that for you.
The comma doesn't make it atomic, but there should only be one thread invoking dealloc anyway or else you have much, much larger problems on your hands. Setting instanceVar to nil is unnecessary, it isn't safer, because if there is a bug in your program that somehow uses the dangling value in instanceVar it will only manifest differently depending on whether it is nil or something else, either way, there is a bug, because nothing should be relying on that value.
With ARC this is even less of an issue. A dealloc method in ARC is only used to release non-ARC-controlled resources, everything else is automatically handled for you.
Related
When compiling with ARC, method arguments often appear to be retained at the beginning of the method and released at the end. This retain/release pair seems superfluous, and contradicts the idea that ARC "produces the code you would have written anyway". Nobody in those dark, pre-ARC days performed an extra retain/release on all method arguments just to be on the safe side, did they?
Consider:
#interface Test : NSObject
#end
#implementation Test
- (void)testARC:(NSString *)s
{
[s length]; // no extra retain/release here.
}
- (void)testARC2:(NSString *)s
{
// ARC inserts [s retain]
[s length];
[s length];
// ARC inserts [s release]
}
- (void)testARC3:(__unsafe_unretained NSString *)s
{
// no retain -- we used __unsafe_unretained
[s length];
[s length];
// no release -- we used __unsafe_unretained
}
#end
When compiled with Xcode 4.3.2 in release mode, the assembly (such that I'm able to understand it) contained calls to objc_retain and objc_release at the start and end of the second method. What's going on?
This is not a huge problem, but this extra retain/release traffic does show up when using Instruments to profile performance-sensitive code. It seems you can decorate method arguments with __unsafe_unretained to avoid this extra retain/release, as I've done in the third example, but doing so feels quite disgusting.
See this reply from the Objc-language mailing list:
When the compiler doesn't know anything about the
memory management behavior of a function or method (and this happens a
lot), then the compiler must assume:
1) That the function or method might completely rearrange or replace
the entire object graph of the application (it probably won't, but it
could). 2) That the caller might be manual reference counted code, and
therefore the lifetime of passed in parameters is not realistically
knowable.
Given #1 and #2; and given that ARC must never allow an object to be
prematurely deallocated, then these two assumptions force the compiler
to retain passed in objects more often than not.
I think that the main problem is that your method’s body might lead to the arguments being released, so that ARC has to act defensively and retain them:
- (void) processItems
{
[self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]];
[self doSomethingSillyWith:[items lastObject]];
}
- (void) doSomethingSillyWith: (id) foo
{
[self setItems:nil];
NSLog(#"%#", foo); // if ARC did not retain foo, you could be in trouble
}
That might also be the reason that you don’t see the extra retain when there’s just a single call in your method.
Passing as a parameter does not, in general, increase the retain count. However, if you're passing it to something like NSThread, it is specifically documented that it will retain the parameter for the new thread.
So without an example of how you're intending to start this new thread, I can't give a definitive answer. In general, though, you should be fine.
Even the answer of soul is correct, it is a bit deeper than it should be:
It is retained, because the passed reference is assigned to a strong variable, the parameter variable. This and only this is the reason for the retain/release pair. (Set the parameter var to __weak and what happens?)
One could optimize it away? It would be like optimizing every retain/release pairs on local variables away, because parameters are local variables. This can be done, if the compiler understands the hole code inside the method including all messages sent and functions calls. This can be applied that rarely that clang even does not try to do it. (Imagine that the arg points to a person (only) belonging to a group and the group is dealloc'd: the person would be dealloc'd, too.)
And yes, not to retain args in MRC was a kind of dangerous, but typically developers know their code that good, that they optimized the retain/release away without thinking about it.
It will not increment behind the scenes. Under ARC if the object is Strong it will simply remain alive until there are no more strong pointers to it. But this really has nothing to do with the object being passed as a parameter or not.
What I am doing is to check the retainCount after allocating the obj and after releasing this obj. Like below
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
TestClass *ptr = [[TestClass alloc] init];
NSLog(#"retain count of ptr is %d",[ptr retainCount]);
[ptr release];
NSLog(#"Right after release:::::retain count of ptr is %d",[ptr retainCount]);
}
What is getting after display on the console is
2012-05-11 13:51:09.515 memoryManagement[1807:f803] retain count of ptr is 1
2012-05-11 13:51:09.516 memoryManagement[1807:f803] Right after release:::::retain count of ptr is 1
I don't why the retainCount after releasing is still 1. Should it be 0.
Please advice me on this issue and point out if I have just made a mistake in my code.
The first rule of Cocoa Club is: don't use -retainCount. The second rule of Cocoa Club is don't use -retainCount.
First off, if you think you need it, you almost certainly don't. If you are using it to debug, you are using the wrong tool. If you are using it for application logic, you have a broken design.
Second, if you have to ask a StackOverflow question about it, you definitely don't need it.
Third, it's subtle, unreliable, can do wacky things behind your back, and generally will cause more headaches than you can possibly imagine. I recommend Bill Bumgarner's blog post.
The actual retain count of an object can never be zero, because when it's zero, nothing has a reference to it, and it is deallocated. The memory doesn't actually get cleared, though, and it looks like the internal release code doesn't bother actually decrementing the count.
Further, you're violating memory management rules; you've got an object that you own, which you then release. You're not allowed to interact with that object through that pointer anymore.
Nothing to see here, and don't bother looking at an object's retain count.
You have an even worse problem than using retainCount.
Never send messages to objects you release -- especially if you have some reason to think their retainCount is really 1. Maybe release is written something like this:
-(void) release {
if ([self retainCount] == 1) {
[self dealloc];
}
else {
// reduce the retain count
}
}
In that case, the object is gone. You send the message, and if the object is somehow still living in deallocated memory, it would report a retainCount of 1 -- no one says release needs to decrement it if it's being deallocated (who would know?).
Once you call release -- you promised never to send messages to the object -- if you break your promise, anything can happen.
The Apple docs explain why retainCount is not what you think it might be
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html
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.
The docs also explain whey you sometimes see a giant number instead of what you think the retainCount should be:
For objects that never get released (that is, their release method does nothing), this method should return UINT_MAX.
This has nothing to do with your case though. If you call retain on ptr right after you init, you will likely see the retainCount as 2 and 1 (or N and N-1), but are not guaranteed that this is true. retainCount is more logical than a lot of these answers would have you believe, but it can't be used in the way you want to reliably.
Never use retainCount. It is confusing and never gives you a clear answer. Also, If you are correctly following memory management guidelines, you would never need to use retaincount.
On most occasions, it gives you ambiguous output.
Eg. [NSString stringwithstring:#"apple"] has a garbage value as retaincount like 1124523415 etc.
So, never trust retainCount.
I'm pretty new to Objective-C, as you may gather, and until recently, I hadn't really understood the need for all this AutoRelease malarky. I think that's mostly because I've started Objective-C with ARC, and haven't had any exposure to doing retains and release.
Anyway, my understanding now is that pre-ARC, if you created an object and needed to return a pointer to it as the returning object of the method/function, you would need to autorelease it, because you are unable to do the "[obj release]" after doing "return obj;"
Worrying about retains and releases isn't an issue with ARC. Does this mean that in our own code, there is really point in creating our own autoreleased objects? Ie, doing [[[Class alloc] init] autorelease]? From what I've gathered, we should still setup autorelease pools, but only because other frameworks or libraries may still return autoreleased objects, but we no longer need to explicitly create autoreleased objects ourselves - is this a fair understanding?
Thanks,
Nick
When using ARC, you do not want to do any memory management yourself. Specifically you will not be calling release and auto release because it does it all for you. In fact, the compiler should probably complain if you try to manage memory yourself.
Instead of [[[Class alloc] init] autorelease]; you'll just call [[Class alloc] init];
I recommend reading this blog post for some really good background on ARC and memory management in general.
Well, your understanding is quite correct. With ARC we do not release or autorelease any more. Just have to make sure that we assign nil (or some other reasonable value) to any reference to objects, which we do not need any more. In the worst case we could still constantly consume additional memory but the memory cannot leak any ore.
And yes, we still maintain autorelease pools for the sake of using framework libraries (linked ones) that may not use ARC.
To answer your question between the lines about the purpose of autorelease. This applies to non-ARC project only, of course.
In the good old days Objective-C did not offer any reference counting but its retain counting. Any allocated memory of objects, that are not retained (or have a retain count of 0) is considered free and may soon be claimed and used by other objects.
This means that every object needs to be retained after its allocation, assuming that you want to keep it around. When the object is not used any more then you need to release it. This comes with two risks. Well, alloc does retain it once automatically.
1) You may forget to release an object that is unused. In the worst case you may even loose all references to an object that stays in memory for ever since.
2) You may still refer to an object hat has been released already and then try accessing it which will most likely end in an BAD_EXC exception.
All this can be quite annoying. In order to get rid of some of these obligations for objects that don't stay around very long, the autorelease was invented. For temporary objects only you alloc it (release-count = 1) and autorelease it. That means that the object will be automatically released (retain count reduced by 1) within the next autorelease circle. But the object remains allocated for your method while it is being executed. Typically the reference variable would be a local one.
Sample:
-(void) myMethod{
AClass *someObject = [[[AClass alloc] init] autorelease];
// use the object
// probably hand it to another object if that takes ownership, i.e. add it ot an Array using addObject:
// don't care any more
}
And that not required any more when using ARC.
I am still new to this Memory Management stuff (Garbage Collector took care of everything in Java), but as far as I understand if you allocate memory for an object then you have to release that memory back to the computer as soon as you are finished with your object.
myObject = [Object alloc];
and
[myObject release];
Right now I just have 3 parts in my Objective-C .m file: #Interface, #Implementation and main. I released my object at the end of the program next to these guys:
[pool drain];
return 0;
But what if this program were to be a lot more complicated, would it be okay to release myObject at the end of the program?
I guess a better question would be when do I release an object's allocated memory? How do I know where to place [myObject release];?
This is probably a little over-simplified, but in general, you are going to want to release it where you declared it.
If you declare an object INSIDE a particular method call, then by definition, you will be done with that object (or at least that handle to that object) at the end of that method call... release it then.
If you declare an object as an instance variable, then by definition you will be done with it when that instance is destroyed... release it in the dealloc method of that class.
Keep in mind that "release" does not equal "destroy." When passing objects around in your application, it may make sense to have more than one handle to that object stored in different places... in that case "release" means "I'm done with this object, but someone else may still be using it." Deallocation only occurs when the number of "handles" (retain count) reaches zero.
Apple has some fantastic documentation on memory management, I would check it out at developer.apple.com.
You essentially have three kinds of objects, each with a different pattern.
Transients Objects
In general, you should autorelease transient objects. These are objects that are allocated locally and do not need to exist beyond the method in which they are called. Or they are passed around from method to method.
Chain of Ownership
When one object exists as an instance field inside another, you should release the "owned" (or "child") object when the "owner" (or "parent") object goes out of existence. This is done in the dealloc method of the parent object:
- (void) dealloc {
[child release]; // child was declared as an instance variable
[super dealloc];
}
Lifetime of the Program
When an object is intended to exist for the lifetime of the program, it usually isn't necessary to call release at all, unless some kind of resource cleanup needs to occur. You can put this in applicationWillTerminate:, which you can look up in Apple's documentation.
(You should probably avoid having such objects, but that is a discussion for another question.)
You have to think in terms of ownership. When you take ownership of an object by calling alloc, new or retain, you're also responsible for releasing it, either by calling autorelease when you return an owned object to the caller, or by calling release.
A general rule is:
Local variable: release it within the same method. When you want to return it to the caller, use autorelease
Class member: release it in the dealloc method
Can someone explain the difference between these two, the first one is taken from allowing xcode to automatically generate the declaration, the last one is taken from an example in "Cocoa Programming" by Aaron Hillegass.
- (NSString*)planetName {
return [[planetName retain] autorelease];
}
.
- (NSString*)planetName {
return planetName;
}
I am just curious whats going on, my understanding was that the method is returning a pointer to either nil or an existing string object. I don't understand the reason for retaining and then adding to the autorelease pool?
Consider:
NSString *planetName = [myPlanet planetName];
[myPlanet setPlanetName: #"Bob"];
[planetName length];
Without [[planetName retain] autorelease], the above will very likely crash.
retain/autorelease puts the object into the current thread's autorelease pool. That effectively guarantees that the object will remain valid until the pool is drained, which is typically after the current event -- user event, timer firing, etc... -- is done processing.
(1) Use #property and #synthesize. It generates correct getter/setters for you.
(2) Read the Cocoa Memory Management guide. It answers all of these questions quite well.
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
In both cases, yes, they are both returning a pointer to either nil or the string object.
The difference is that the first code block handles memory management, the second does not. The second code block is assuming you are managing planetName somewhere else in your class instance, whereas in the first code block Apple is being as conservative as possible in keeping that memory from leaking. By putting the memory in the current autorelease pool it will be destroyed with the pool.
My recommendation would be to stick with the latter case and to be a little wiser about managing your own object instances than what XCode is auto-generating for you.