views:

245

answers:

3

I was just writing some exploratory code to solidify my understanding of Objective-C and I came across this example that I don't quite get. I define this method and run the code:

- (NSString *)stringMethod
{
    NSString *stringPointer = [[NSString alloc] initWithFormat:@"string inside stringPointer"];
    [stringPointer release];
    [stringPointer release];
    NSLog(@"retain count of stringPointer is %i", [stringPointer retainCount]);
    return stringPointer;
}

After running the code and calling this method, I notice a few things:

  1. Normally, if I try to access something that's supposedly dealloced after hitting zero retain count, I get a EXC_BAD_ACCESS error. Here, I get a malloc "double free" error instead. Why is that?

  2. No matter how many lines of "[stringPointer release]" I add to the code, NSLog reports a retain count of 1. When I add more releases I just get more "double free" errors. Why aren't the release statements working as expected?

  3. Although I've over-released stringPointer and I've received a bunch of "double free" errors, the return value still works as if nothing happened (I have another NSLog in the main code that reports the return value). The program continues to run normally. Again, can someone explain why this happens?

These examples are fairly trivial, but I'm trying to get a full grasp of what's going on. Thanks!

+5  A: 

You're getting a double free error because you are releasing twice and causing two dealloc messages. =P

Keep in mind that just because you release doesn't doesn't mean the data at its memory address is immediately destroyed. It's just being marked as unused so the kernel knows that, at some point in the future, it is free to be used for another piece of data. Until that point (which is totally nondeterministic in your app space), the data will remain there.

So again: releasing (and dealloc'ing) doesn't necessitate immediate data destruction on the byte level. It's just a marker for the kernel.

Marc W
A: 

The retainCount always printing one is probably caused by optimization - when release notices that its going to be deallocated, there's no reason to update the retainCount to zero (as at this point nobody should have a reference to the object) and instead of updating the retainCount just deallocates it.

Steven Schlansker
+3  A: 

There are a couple of things going on here. First, deallocing an object doesn't necessarily clear any of the memory the object formerly occupied. It just marks it as free. Unless you do something else that causes that memory to be re-used, the old data will just hang around.

In the specific case of NSString, it's a class cluster, which means that the actual class you get back from alloc/init is some concrete subclass of NSString, not an NSString instance. For "constant" strings, this is an extremely light-weight structure that just maintains a pointer to the C-string constant. No matter how many copies of that striing you make, or how many times you release it, you won't affect the validity of the pointer to the constant C string.

Try examining [stringPointer class] in this case, as well as in the case of a mutable string, or a formatted string that actually uses a format character and arguments. Probably all three will turn out to have different classes.

Mark Bessey