I found a strange behavior with NSString. I tried to run the below code and noticed this.
NSString *str = [[NSString alloc] initwithstring : @"hello"];
[str release];
NSLog(@" Print the value : %@", str);
Here, in the third line app should crash because we are accessing an object which is released. But it is printing the value of str. It is not crashing. But with NSArray i observed different behavior.
NSArray *array = [[NSArray alloc] initwithobjects : @"1", @"2", nil];
[array release];
NSLog(@"Print : %@", [array objectatindex : 0]);
NSLog(@"Print : %@", [array objectatindex : 0]);
The code has two NSLog statements used for NSArray. Here after releasing when the first NSLog is executed, it is printing value. But when second NSLog is executed, app crashes. App crash is acceptable because the array accessed was released already. But it should crash when the first NSLog is executed. Not the second one.
Help me with this behaviors. How release works in these cases.
Thanks Jithen
The first example doesn't crash because string literals are never released. The code is really:
NSString *str = @"hello";
[str release];
People get burned with string literals on memory management and mistakenly using ==
to compare them instead of isEqualToString:
. The compiler does some optimizations that lead to misleading results.
Update:
The following code proves my point:
NSString *literal = @"foo";
NSString *second = [NSString stringWithString:literal];
NSString *third = [NSString stringWithString:@"foo"]; // <-- this gives a compiler warning for being redundant
NSLog(@"literal = %p", literal);
NSLog(@"second = %p", second);
NSLog(@"third = %p", third);
This code gives the following output:
2013-02-28 22:03:35.663 SelCast[85617:11303] literal = 0x359c
2013-02-28 22:03:35.666 SelCast[85617:11303] second = 0x359c
2013-02-28 22:03:35.668 SelCast[85617:11303] third = 0x359c
Notice that all three variable point to the same memory.
Your second example crashes at the second NSLog
because at the first log, the memory where array
was hasn't been re-used, but that first log causes enough activity on the heap to cause the memory to become used by something else. Then, when you try to access it again, you get a crash.
Whenever an object is deallocated and its memory marked as free, there is going to be some period of time where that memory still stores what's left of that object. During this time you can still call methods on such objects and so forth, without crashing. This time is extremely short, and if you're running a lot of threads it may not even be enough to get your method call in. So clearly, don't rely on this implementation detail for any behavior.
As others have said, regarding your first question, NSString
literals aren't going to be deallocated. This is true for some other Foundation classes (NSNumber
comes to mind) but is an implementation detail as well. If you need to do experiments on memory management, use an NSObject
instance instead, as it will not show the unusual behaviors.
When you send a release
message on an object, the object is actually not being removed from the memory. The release message simply decrements the reference count by one only. If the reference count is zero the object is marked as free. Then the system remove it from the memory. Until this deallocation happens you can access your object. Even if you release
the object your object pointer still points to the object unless you are assigning nil
to the pointer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With