Why not release memory after use NSMutableArray - ios

Let's assume we create a new MacOS application with Xcode and adding some code inside the [viewDidLoad].
The memory is not fully released after running. Why? How to release the memory?
Example code:
NSMutableArray *a = [NSMutableArray array];
for(int i=0;i<8000000;i++){
[a addObject:[NSValue valueWithPoint:NSMakePoint(i, 0)]];
}
a = nil;
I can see the imformation about memory by a button which name is "show the debug navigator" by Xcode

First let's have look on what you have done:
NSMutableArray *a = [NSMutableArray array];
for(int i=0;i<8000000;i++){
[a addObject:[NSValue valueWithPoint:NSMakePoint(i, 0)]];
}
a = nil;
You create an array in the autorelease pool and you create a number of value objects in the autorelease pool. The autoreleased array holds the value objects.
A. As long as there is an autorelease pool in place, none of the objects will be released. The autorelease pool retains them. Therefore setting a to nil will not really help. As long as the autorelease pool retains an object, giving up a private reference cannot take the reference count to 0.
There are two techniques to avoid that:
a. As mentioned by #sunshine you can install a local autorelease pool. This will hold the objects instead of the more global autorelease pool, releasing the objects earlier. (But as said by #HotLicks, if should be placed outside the whole snippet.)
b. Do not create the objects in the autorelease pool.
NSMutableArray *a = [NSMutableArray new]; // new is ownership transfer
for(int i=0;i<8000000;i++) {
CGPoint point = NSMakePoint( i, 0 );
[a addObject:[[NSValue alloc] initWithBytes:&point withObjCType:withObjCType:#encode(CGPoint)];
}
a = nil;
B. It is possible that you still have "spooky" objects. Likely this is, because some value classes (i. e. NSNumber) does never free some objects considered to be re-used in near future. Maybe NSValue does the same, when using valueWithPoint:. That there is no corresponding -initWithPoint: is a pointer for that.
You can expect better information, if you tell us, how you measured the memory consumption. "ARC" is no answer to this question, because it is a memory management model, no memory measurement tool.

If you're using ARC then you don't care about releasing at all. If you run this code under manual memory management mode then you still don't have to worry about the memory in this case because both array and the objects it holds are autoreleased. So this code is completely ok and can't cause any memory leaks

You can use #autoreleasepool:
#autoreleasepool {
for(int i=0;i<8000000;i++){
[a addObject:[NSValue valueWithPoint:NSMakePoint(i, 0)]];
}
}

Using ARC doesn't guarantee that your objects will get released or tell you when they get released. Everything is done automatically behind the scenes.
When I'm saying that your objects are not guaranteed to be released think about retain(strong) cycles which they're still a reality even with ARC.
So, your code is fine at this point but if you want to force a release, as a colleague mentioned, embed your local objects into an #autoreleasepool block which will be drained when its execution finishes.

Related

How does ARC work in loops? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I search a lot of information but couldn't find anything. Maybe I can't search well) As I know ARC work like compile tool. This tool actually instead of developer sets release and retains in assembler code. But my questions is how it will work if, for example, we create objects in loop of random value?
int value = arc4random_uniform(74);
for(int i=0; i<value; ++i) {
MyObject* my = [MyObject new];
}
So how it will be resolved, because on compile time we don't know count of objects. If it works like after MyObject* my = [MyObject new]; arc just add [my release]; why we should use autoreleasepool if it will be released at the moment???
It depends on the whims of the compiler and it may change depending on targeted architecture, OS version and/or compiler optimization settings.
The # of passes through the loop doesn't matter.
Effectively, this:
for(int i=0; i<value; ++i) {
MyObject* my = [MyObject new];
}
Might be compiled as:
for(int i=0; i<value; ++i) {
MyObject* my = [[MyObject new] autorelease];
}
Or this:
for(int i=0; i<value; ++i) {
MyObject* my = [MyObject new];
[my release];
}
Both are perfectly valid.
Through profiling, you might find you need to surround a for() loop's body with #autoreleasepool {} if there is a ton of autorelease noise being generated by the loop. Maybe. Generally, though, a ton of autorelease pool traffic is indicative of an algorithmic problem. Optimizing away memory thrash is oft critical to performance.
You said
As I know ARC work like compile tool. ... So how [will autorelease objects] be resolved, because on compile time we don't know count of objects.
ARC is a compile time tool, but autorelease objects aren't managed by ARC. They're managed by the autorelease pool, which is handled at runtime. So, as autorelease objects are created, they're added to the current pool, and when the pool is drained (either by yielding back to the OS or by creating your own manual autorelease pools) those autorelease references are released.
why we should use autoreleasepool if it will be released at the moment???
By definition, autoreleased objects are not released at the moment. They're only released when the pool is drained.
As the compiler and ARC have evolved, it's gotten increasingly sophisticated about not creating autorelease objects, but rather creating objects that ARC will manage for you. You seem to be assuming that your code snippet will generate autorelease objects, but as bbum said, you have no such assurances. It's most likely managed by ARC, not the autorelease pool.
I would suggest profiling your app through the "Allocations" tool of "Instruments" and watching the memory usage there. If you see unbridled memory growth there which is only resolved when the loop finished, then you might have autorelease objects involved and putting an autorelease pool in your loop might be warranted. Otherwise, don't worry about it, as it's increasingly likely that no autorelease objects are involved.
ARC is not magic. It's complicated, but it's not magic.
Let's look at your example
int value = arc4random_uniform(74);
for(int i=0; i<value; ++i) {
MyObject* my = [MyObject new];
}
Assuming MyObject is based on NSObject and has not been overridden with a different return value, then we need to check the declaration of new in NSObject.
+ (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
NOTE: No ARC declaration is made.
The default ARC setting is used, because there is no ARC declaration.
So the next question is, "what is the default?" Now we check the documenation: Objective-C Automatic Reference Counting (ARC).
Methods in the alloc, copy, init, mutableCopy, and new families are implicitly marked __attribute__((ns_returns_retained)). This may be suppressed by explicitly marking the method __attribute__((ns_returns_not_retained)).
-new is in the new family, so the default is to have __attribute__((ns_returns_retained)).
MyObject will return retain +1 and will not be auto-released.
int value = arc4random_uniform(74);
for(int i=0; i<value; ++i) {
MyObject* my = [MyObject new]/* Implied [my retain] */;
/* Implied [my release] */}

atomic make the retainCount+1

I don't often use property atomic, but I found something is strange. My test file is not use ARC.
I use a property #property(atomic,retain) NSArray* test;
Then I just make a test for the thing in the init method.
like this
1) NSArray* testArray = [NSArray arrayWithObject:#"1"];
2) self.test = testArray;
After executing 1)
[testArray retainCount] = 1
After executing 2)
[testArray retianCount] = 2
[self.test retainCount] = 3
[_test retainCount] = 3.
Then I change property atomic to nonatomic. After executing 1)
[testArray retainCount] = 1
After executing 2)
[testArray retianCount] = 2
[self.test retainCount] = 2
[_test retainCount] = 2.
so I don't know why. atomic can add retainCount?
You shouldn't do Manual Reference Counting in this day and age. Seriously, there is no drawback to using ARC. The only reason I can think of is, if you need to maintain legacy code that can't be converted to ARC (due to resource allocation priorities, etc.).
Even back in the days of MRC, Apple strongly discouraged the direct manipulation of the retainCount property: that is just an implementation detail and relying on it will just make your app fragile.
You should instead design your app around object graphs (ownership relationships), whether with ARC or MRC.
I think atomic put a object to current Autorelease poll. It is needed to make the object alive while you work with it (in this moment the object may be released on an other thread).
Try to wrap
NSArray* testArray = [NSArray arrayWithObject:#"1"];
self.test = testArray;
with AutoreleasePool, and check retainCount after (Then code exit from autorelease poll).
I think you will get retainCount == 1.
The absolute value of the retainCount is completely useless. You can't infer meaning from it about an objects lifespan nor is it particularly useful for debugging.
See http://www.whentouseretaincount.com for more information.
As for your specific case, the retain count is changing behavior across atomic due to implementation details. If you switch between optimized and non-optimized builds, you'll probably see yet different results.

When to use the autorelease pool [duplicate]

For the most part with ARC (Automatic Reference Counting), we don't need to think about memory management at all with Objective-C objects. It is not permitted to create NSAutoreleasePools anymore, however there is a new syntax:
#autoreleasepool {
…
}
My question is, why would I ever need this when I'm not supposed to be manually releasing/autoreleasing ?
EDIT: To sum up what I got out of all the anwers and comments succinctly:
New Syntax:
#autoreleasepool { … } is new syntax for
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
…
[pool drain];
More importantly:
ARC uses autorelease as well as release.
It needs an auto release pool in place to do so.
ARC doesn't create the auto release pool for you. However:
The main thread of every Cocoa app already has an autorelease pool in it.
There are two occasions when you might want to make use of #autoreleasepool:
When you are in a secondary thread and there is no auto release pool, you must make your own to prevent leaks, such as myRunLoop(…) { #autoreleasepool { … } return success; }.
When you wish to create a more local pool, as #mattjgalloway has shown in his answer.
ARC doesn't get rid of retains, releases and autoreleases, it just adds in the required ones for you. So there are still calls to retain, there are still calls to release, there are still calls to autorelease and there are still auto release pools.
One of the other changes they made with the new Clang 3.0 compiler and ARC is that they replaced NSAutoReleasePool with the #autoreleasepool compiler directive. NSAutoReleasePool was always a bit of a special "object" anyway and they made it so that the syntax of using one is not confused with an object so that it's generally a bit more simple.
So basically, you need #autoreleasepool because there are still auto release pools to worry about. You just don't need to worry about adding in autorelease calls.
An example of using an auto release pool:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
#autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(#"number = %p", number);
}
}
}
}
A hugely contrived example, sure, but if you didn't have the #autoreleasepool inside the outer for-loop then you'd be releasing 100000000 objects later on rather than 10000 each time round the outer for-loop.
Update:
Also see this answer - https://stackoverflow.com/a/7950636/1068248 - for why #autoreleasepool is nothing to do with ARC.
Update:
I took a look into the internals of what's going on here and wrote it up on my blog. If you take a look there then you will see exactly what ARC is doing and how the new style #autoreleasepool and how it introduces a scope is used by the compiler to infer information about what retains, releases & autoreleases are required.
#autoreleasepool doesn't autorelease anything. It creates an autorelease pool, so that when the end of block is reached, any objects that were autoreleased by ARC while the block was active will be sent release messages. Apple's Advanced Memory Management Programming Guide explains it thus:
At the end of the autorelease pool block, objects that received an autorelease message within the block are sent a release message—an object receives a release message for each time it was sent an autorelease message within the block.
People often misunderstand ARC for some kind of garbage collection or the like. The truth is that, after some time people at Apple (thanks to llvm and clang projects) realized that Objective-C's memory administration (all the retains and releases, etc.) can be fully automatized at compile time. This is, just by reading the code, even before it is run! :)
In order to do so there is only one condition: We MUST follow the rules, otherwise the compiler would not be able to automate the process at compile time. So, to ensure that we never break the rules, we are not allowed to explicitly write release, retain, etc. Those calls are Automatically injected into our code by the compiler. Hence internally we still have autoreleases, retain, release, etc. It is just we don't need to write them anymore.
The A of ARC is automatic at compile time, which is much better than at run time like garbage collection.
We still have #autoreleasepool{...} because having it does not break any of the rules, we are free create/drain our pool anytime we need it :).
Autorelease pools are required for returning newly created objects from a method. E.g. consider this piece of code:
- (NSString *)messageOfTheDay {
return [[NSString alloc] initWithFormat:#"Hello %#!", self.username];
}
The string created in the method will have a retain count of one. Now who shall balance that retain count with a release?
The method itself? Not possible, it has to return the created object, so it must not release it prior to returning.
The caller of the method? The caller does not expect to retrieve an object that needs releasing, the method name does not imply that a new object is created, it only says that an object is returned and this returned object may be a new one requiring a release but it may as well be an existing one that doesn't. What the method does return may even depend on some internal state, so the the caller cannot know if it has to release that object and it shouldn't have to care.
If the caller had to always release all returned object by convention, then every object not newly created would always have to be retained prior to returning it from a method and it would have to be released by the caller once it goes out of scope, unless it is returned again. This would be highly inefficient in many cases as one can completely avoid altering retain counts in many cases if the caller will not always release the returned object.
That's why there are autorelease pools, so the first method will in fact become
- (NSString *)messageOfTheDay {
NSString * res = [[NSString alloc] initWithFormat:#"Hello %#!", self.username];
return [res autorelease];
}
Calling autorelease on an object adds it to the autorelease pool, but what does that really mean, adding an object to the autorelease pool? Well, it means telling your system "I want you to to release that object for me but at some later time, not now; it has a retain count that needs to be balanced by a release otherwise memory will leak but I cannot do that myself right now, as I need the object to stay alive beyond my current scope and my caller won't do it for me either, it has no knowledge that this needs to be done. So add it to your pool and once you clean up that pool, also clean up my object for me."
With ARC the compiler decides for you when to retain an object, when to release an object and when to add it to an autorelease pool but it still requires the presence of autorelease pools to be able to return newly created objects from methods without leaking memory. Apple has just made some nifty optimizations to the generated code which will sometimes eliminate autorelease pools during runtime. These optimizations require that both, the caller and the callee are using ARC (remember mixing ARC and non-ARC is legal and also officially supported) and if that is actually the case can only be known at runtime.
Consider this ARC Code:
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
The code that the system generates, can either behave like the following code (that is the safe version that allows you to freely mix ARC and non-ARC code):
// Callee
- (SomeObject *)getSomeObject {
return [[[SomeObject alloc] init] autorelease];
}
// Caller
SomeObject * obj = [[self getSomeObject] retain];
[obj doStuff];
[obj release];
(Note the retain/release in the caller is just a defensive safety retain, it's not strictly required, the code would be perfectly correct without it)
Or it can behave like this code, in case that both are detected to use ARC at runtime:
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
[obj release];
As you can see, Apple eliminates the atuorelease, thus also the delayed object release when the pool is destroyed, as well as the safety retain. To learn more about how that is possible and what's really going on behind the scenes, check out this blog post.
Now to the actual question: Why would one use #autoreleasepool?
For most developers, there's only one reason left today for using this construct in their code and that is to keep the memory footprint small where applicable. E.g. consider this loop:
for (int i = 0; i < 1000000; i++) {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
Assume that every call to tempObjectForData may create a new TempObject that is returned autorelease. The for-loop will create one million of these temp objects which are all collected in the current autoreleasepool and only once that pool is destroyed, all the temp objects are destroyed as well. Until that happens, you have one million of these temp objects in memory.
If you write the code like this instead:
for (int i = 0; i < 1000000; i++) #autoreleasepool {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
Then a new pool is created every time the for-loop runs and is destroyed at the end of each loop iteration. That way at most one temp object is hanging around in memory at any time despite the loop running one million times.
In the past you often had to also manage autoreleasepools yourself when managing threads (e.g. using NSThread) as only the main thread automatically has an autorelease pool for a Cocoa/UIKit app. Yet this is pretty much legacy today as today you probably wouldn't use threads to begin with. You'd use GCD DispatchQueue's or NSOperationQueue's and these two both do manage a top level autorelease pool for you, created before running a block/task and destroyed once done with it.
It's because you still need to provide the compiler with hints about when it is safe for autoreleased objects to go out of scope.
Quoted from https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html:
Autorelease Pool Blocks and Threads
Each thread in a Cocoa application maintains its own stack of
autorelease pool blocks. If you are writing a Foundation-only program
or if you detach a thread, you need to create your own autorelease
pool block.
If your application or thread is long-lived and potentially generates
a lot of autoreleased objects, you should use autorelease pool blocks
(like AppKit and UIKit do on the main thread); otherwise, autoreleased
objects accumulate and your memory footprint grows. If your detached
thread does not make Cocoa calls, you do not need to use an
autorelease pool block.
Note: If you create secondary threads using the POSIX thread APIs
instead of NSThread, you cannot use Cocoa unless Cocoa is in
multithreading mode. Cocoa enters multithreading mode only after
detaching its first NSThread object. To use Cocoa on secondary POSIX
threads, your application must first detach at least one NSThread
object, which can immediately exit. You can test whether Cocoa is in
multithreading mode with the NSThread class method isMultiThreaded.
...
In Automatic Reference Counting, or ARC, the system uses the same
reference counting system as MRR, but it insertsthe appropriate memory
management method callsfor you at compile-time. You are strongly
encouraged to use ARC for new projects. If you use ARC, there is
typically no need to understand the underlying implementation
described in this document, although it may in some situations be
helpful. For more about ARC, see Transitioning to ARC Release Notes.
TL;DR
Why is #autoreleasepool still needed with ARC?
#autoreleasepool is used by Objective-C and Swift to work with autorelese inside
When you work with pure Swift and allocate Swift objects - ARC handles it
But if you decide call/use Foundation/Legacy Objective-C code(NSData, Data) which uses autorelese inside then #autoreleasepool in a rescue
//Swift
let imageData = try! Data(contentsOf: url)
//Data init uses Objective-C code with [NSData dataWithContentsOfURL] which uses `autorelese`
Long answer
MRC, ARC, GC
Manual Reference Counting(MRC) or Manual Retain-Release(MRR) as a developer you are responsible for counting references on objects manually
Automatic Reference Counting(ARC) was introduced in iOS v5.0 and OS X Mountain Lion with xCode v4.2
Garbage Collection(GC) was available for Mac OS and was deprecated in OS X Mountain Lion. Must Move to ARC
Reference count in MRC and ARC
//MRC
NSLog(#"Retain Count: %d", [variable retainCount]);
//ARC
NSLog(#"Retain Count: %ld", CFGetRetainCount((__bridge CFTypeRef) variable));
Every object in heap has an integer value which indicates how many references are pointed out on it. When it equals to 0 object is deallocated by system
Allocating object
Working with Reference count
Deallocating object. deinit is called when retainCount == 0
MRC
A *a1 = [[A alloc] init]; //this A object retainCount = 1
A *a2 = a1;
[a2 retain]; //this A object retainCount = 2
// a1, a2 -> object in heap with retainCount
Correct way to release an object:
release If only this - dangling pointer. Because it still can point on the object in heap and it is possible to send a message
= nil If only this - memory leak. deinit will not be called
A *a = [[A alloc] init]; //++retainCount = 1
[a release]; //--retainCount = 0
a = nil; //guarantees that even somebody else has a reference to the object, and we try to send some message thought variable `a` this message will be just skipped
Working with Reference count(Object owner rules):
(0 -> 1) alloc, new, copy, mutableCopy
(+1) retain You are able to own an object as many times as you need(you can call retain several times)
(-1) release If you an owner you must release it. If you release more than retainCount it will be 0
(-1) autorelease Adds an object, which should be released, to autorelease pool. This pool will be processed at the end of RunLoop iteration cycle(it means when all tasks will be finished on the stack)[About] and after that release will be applied for all objects in the pool
(-1) #autoreleasepool Forces process an autorelease pool at the end of block. It is used when you deal with autorelease in a loop and want to clear resources ASAP. If you don't do it your memory footprint will be constantly increasing
autorelease is used in method calls when you allocate a new object there and return it
- (B *)foo {
B *b1 = [[B alloc] init]; //retainCount = 1
//fix - correct way - add it to fix wrong way
//[b1 autorelease];
//wrong way(without fix)
return b;
}
- (void)testFoo {
B *b2 = [a foo];
[b2 retain]; //retainCount = 2
//some logic
[b2 release]; //retainCount = 1
//Memory Leak
}
#autoreleasepool example
- (void)testFoo {
for(i=0; i<100; i++) {
B *b2 = [a foo];
//process b2
}
}
ARC
One of biggest advantage of ARC is that it automatically insert retain, release, autorelease under the hood in Compile Time and as developer you should not take care of it anymore
Enable/Disable ARC
//enable
-fobjc-arc
//disable
-fno-objc-arc
Variants from more to less priority
//1. local file - most priority
Build Phases -> Compile Sources -> Compiler Flags(Select files -> Enter)
//2. global
Build Settings -> Other C Flags(OTHER_CFLAGS)
//3. global
Build Settings -> Objective-C Automatic Reference Counting(CLANG_ENABLE_OBJC_ARC)
Check if ARC is enabled/disabled
Preprocessor __has_feature function is used
__has_feature(objc_arc)
Compile time
// error if ARC is Off. Force to enable ARC
#if ! __has_feature(objc_arc)
#error Please enable ARC for this file
#endif
//or
// error if ARC is On. Force to disable ARC
#if __has_feature(objc_arc)
#error Please disable ARC for this file
#endif
Runtime
#if __has_feature(objc_arc)
// ARC is On
NSLog(#"ARC on");
#else
// ARC is Off
NSLog(#"ARC off");
#endif
Reverse engineering(for Objective-C)
//ARC is enabled
otool -I -v <binary_path> | grep "<mrc_message>"
//e.g.
otool -I -v "/Users/alex/ARC_experiments.app/ARC_experiments" | grep "_objc_release"
//result
0x00000001000080e0 748 _objc_release
//<mrc_message>
_objc_retain
_objc_release
_objc_autoreleaseReturnValue
_objc_retainAutoreleaseReturnValue
_objc_retainAutoreleasedReturnValue
_objc_storeStrong
Tool to Migrate Objective-C MRC to ARC
ARC generates errors where you should manually remove retain, release, autorelease and others issues
Edit -> Convert -> To Objective-C ARC...
New Xcode with MRC
If you enable MRC you get next errors(warnings)(but the build will be successful)
//release/retain/autorelease/retainCount
'release' is unavailable: not available in automatic reference counting mode
ARC forbids explicit message send of 'release'
There seems to be a lot of confusion on this topic (and at least 80 people who probably are now confused about this and think they need to sprinkle #autoreleasepool around their code).
If a project (including its dependencies) exclusively uses ARC, then #autoreleasepool never needs to be used and will do nothing useful. ARC will handle releasing objects at the correct time. For example:
#interface Testing: NSObject
+ (void) test;
#end
#implementation Testing
- (void) dealloc { NSLog(#"dealloc"); }
+ (void) test
{
while(true) NSLog(#"p = %p", [Testing new]);
}
#end
displays:
p = 0x17696f80
dealloc
p = 0x17570a90
dealloc
Each Testing object is deallocated as soon as the value goes out of scope, without waiting for an autorelease pool to be exited. (The same thing happens with the NSNumber example; this just lets us observe the dealloc.) ARC does not use autorelease.
The reason #autoreleasepool is still allowed is for mixed ARC and non-ARC projects, which haven't yet completely transitioned to ARC.
If you call into non-ARC code, it may return an autoreleased object. In that case, the above loop would leak, since the current autorelease pool will never be exited. That's where you'd want to put an #autoreleasepool around the code block.
But if you've completely made the ARC transition, then forget about autoreleasepool.

Multiple allocation and nil pointer assignment memory concepts

What happens when I allocate init an object multiple times?
For example:
{
nssstring * samplestring ;
samplestring = [[nsstring alloc]init];
samplestring = [[nsstring alloc]init];
}
Is the memory address that samplestring points on first allocation a leak after this code block execution?
Is this normal or a BAD CODING PRACTICE.
How Does ARC handles the first memory allocation after this bloc execution.
2.How is the above code different from
{
nssstring * samplestring;
samplestring = [[nsstring alloc]init];
samplestring = nil;
}
Nil is an object. Right ? So it seems here too that the first samplestring memory allocation would behave similar to the code block in 1. Or does nil have special significance in memory management.
Finally if I want to use the same object name should I follow 1 or 2.
I am asking this question from my phone so please excuse the formatting, and in case this is a duplicate.
For 1, when you re-assign an object pointer, ARC will destroy the old object. Similarly, if the object goes out-of-scope, it will be destroyed
{
NSString * samplestring ;
samplestring =[ [nsstring alloc]init]; // first object created
samplestring =[ [nsstring alloc]init]; // first destroyed, second created
} // second object destroyed
For 2, this is pretty much the same story, except there is nothing to destroy when the symbol goes out-of-scope:
{
NSString * samplestring;
samplestring =[ [nsstring alloc]init]; // first object created
samplestring =nil; // first object destroyed
}
As for Finally if I want to use the same object name should I follow 1 or 2., it doesn't really matter, however 2. is redundant as ARC will manage the object lifetime correctly.
And finally, nil is not an object, it's a nil pointer, i.e. a pointer to nothing.
If you are using ARC then there is no leak in either of those two cases.
In the first example you create a pointer. Then you create an object in memory and tell the pointer to point to it. Then you create another object in memory (at a different memory location) and tell the pointer to point to it. ARC will see that nothing points to the first allocation anymore and mark the memory location as garbage and re-usable. ARC adds in the retain] and release calls for you based on when the objects are pointed to or not (have a retian count of 1 or more).
Your second example is pretty much the same. You create a pointer. then you create an object and tell the pointer to point to it. then you tell the pointer to point to nothing (zero). At that point you have nothing pointing to the memory location that you created, ARC sees that and marks the memory as garbage/re-usable.
In some ways the second example is better because then when you run analyze with xcode it will see that you set the pointer to nil and any further uses of it without reassignment will be flagged as errors (if they didn't cause your app to crash in the first place). But it's really a matter of opinion.

Memory management Objective - C

I was reading memory management tutorial on iOS and I would like to ask some questions.
The tutorial presents a setter method implemented like this:
- (void)setCount:(NSNumber *)newCount {
[newCount retain];
[_count release];
// Make the new assignment.
_count = newCount;
}
and two ways of implementing reset method.
Method 1.
My question on this method is like this. Below in the code, one can see
zero is assigned to _count (via setCount). But afterwards zero is released.
Where will _count be pointing to now? Will it not cause situation where
_count is pointing to an object which was released? (I am just starting with these
things, so what I am saying of course maybe not correct).
- (void)reset {
NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
[self setCount:zero];
[zero release];
}
Method 2.
Here I am interested who will release zero now? (It must be released right because it was created using alloc). Will it be done in dealloc?
- (void)reset {
NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
[_count release];
_count = zero;
}
Thanks.
That tutorial is slightly broken. Bug filed. It'll be fixed someday.
First, since you are learning, you should use ARC. Even if you don't use ARC, you should use #property to declare everything.
So, you'd have in your header:
#property(strong) NSNumber *count;
And that would both create the setter/getter methods automatically and it would also create an instance variable named _count.
Next, by doing the above, the setter/getter will be created with the proper memory management retain/release patterns and you don't have to worry about it. Less code is better.
Finally, any object goes through three distinct phases. Initialization, operating lifespan, deallocation.
During initialization and deallocation, it is recommended that you manage your instance variables directly. I.e.:
- init {
self = [super init];
if (self) {
_count = [[NSNumber alloc] initWithInteger:0]; // RC +1
}
return self;
}
- (void)dealloc {
[_count release]; /// RC -1
[super dealloc];
}
Note that I'm setting the instance variable directly and that the retain in the init is balanced by the release in dealloc.
Now, during the operating lifespan, you should always use the setter to change the value. This allows the setter to be overridden in subclasses to add logic (which, really, should be avoided -- keep your setters dead simple) and it allows other objects to observe the state of your object through Key Value Observing.
Thus:
- (void)reset {
[self setCount: [[[NSNumber alloc] initWithInteger:0] autorelease]]; // RC +1, -1 (delayed)
}
Now, that looks a little weird. The alloc bumps the retain count by 1, then the setCount: method will likely (it might not, implementation detail, you don't care) bump the retain count by one. That autorelease exists to balance the alloc.
Note that you can shorten it:
- (void)reset {
[self setCount: [NSNumber numberWithInteger:0]];
}
The above code does exactly the same as the first in that numberWithInteger: creates an autoreleased instance of NSNumber.
Or, even:
- (void)reset {
[self setCount: #0];
}
#0 is a new syntactical shorthand for [NSNumber numberWithInteger:0];.
The key, here, is that in your reset method you don't have to know or care about what setCount: does to the object. If it is written correctly -- and it will be since you are using automatically synthesized getter/setter -- that method will either retain the object (releasing the previous one) or it might make a copy of the object.
Bottom line:
Reference counting is quite simple; always think of it as balanced deltas. For every retain, there must be a release.
Both cases do the same, they just differ in style.
In the first one setCount will increase the releaseCount so that when zero is released in reset there is sill a pointer to it.
In the second case zero is assigned to _count, the zero is released when it is replaced in reset as it is pointed to be _count.
In both cases dealloc will also need to realease the _count attribute.
The reason to prefer the second is given in the Apple document you link to as
The following will almost certainly work correctly for simple cases, but as tempting as it may be to eschew accessor methods, doing so will almost certainly lead to a mistake at some stage (for example, when you forget to retain or release, or if the memory management semantics for the instance variable change).
As in #powerj1984 comment you probably should uses ARC and properties and so not have to do this manually so even less chance of making an error, but you should still understand how these code examples work.
The convention is that every time an object is initialized with a method that starts with the word init, its retain count is increased by one.
For Method 1:
After NSNumber *zero = [[NSNumber alloc] initWithInteger:0]; the retain count the object referred by the pointer zero is RC+1.
Then after calling [self setCount:zero]; the object referred by zero becomes RC+2, because of the retain message sent inside that method.
Finally, after [zero release]; the retain count for zero is decreased again to RC+1.
For Method 2
As explained above, the call to NSNumber *zero = [[NSNumber alloc] initWithInteger:0]; initializes zero with a retain count of RC+1.
Then [_count release]; decreases the retain count of the previous object referred to by _count and _count = zero; assigns zero to _count without going through the setter, thus mantaining the retain count at RC+1.
Finally, both in the first and second ways, _count must be released inside the -(void)dealloc method which you must implement, and which will be called automatically once the class where all this is happening gets released by whichever class owns it decreasing its retain count by one and relinquishing ownership of the object.
The second way is correct but wrong, in the sense that it works but is not correct the way you keep that reference. Memory management is based on ownership that is count by the reference count.
Thus in the second way you:
you create and object RC=1 for zero
you release the ownership on an old object, the RC of that object
could be zero or more maybe some other object is taking ownership on
it
you pass a value, but you are not asking for its ownership
And that is conceptually wrong and could lead to problems in bigger code
I think you are confusing the meaning of "release" and "deallocation".
Calling [A release] does not deallocate (c++-speak: delete) A, it rather only decreases the retainCount of A by one.
An object, once created by -init has a retainCount of 1. The retainCount is incremented by sending the object the -retain selector, and it is decremented by sending the object a -release selector. The object is deallocated automatically by the runtime when its retainCount reaches zero.
In your example the first line of -reset ([self setCount:zero]) will increase the retainCount of zero, the second line ([zero release]) will decrement the same, leaving the object at a retain count of 1 (so, it is still alive!).
Deallocation of zero will happen when -setCount: is called with another object, or in the deallocator of the object which owns the property "count". For this you should add an deallocator like this, or you will create a memory leak.
-(void)dealloc{
[_count release];
[super dealloc]
}
For completeness, you should also know about:
The -autorelease selector and NSAutoreleasePool (google it)
Objects created by a static member are already autoreleased by convention
Consider to use Objective-C's ARC (automatic reference count)
If you are targeting iOS5+ (which is running on at least 93% of all iOS devices) please just use Automatic Reference Counting
http://en.wikipedia.org/wiki/Automatic_Reference_Counting
http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
Whining and complaining done.
So if you insist on not using ARC (sigh):
In the first example, NSNumber *zero = [[NSNumber alloc] initWithInteger:0]; is created and its refCount is automatically 1, setCount increases its refcount to 2, release sets its refCount back to one so it won't be deallocated just yet.
In the second example, you create NSNumber *zero = [[NSNumber alloc] initWithInteger:0]; so its refCount is 1, [_count release] decreases the refCount of the object in _count by 1, _count = zero doesn't increase the refCount of zero so its refCount is still 1.
In both cases you're going to have to:
-(void) dealloc {
[_count release]; // release me because my refCount is 1 or else I'll be all
// lonely here in memory by myself :( then I'll get all
// depressed and start eating cookie dough ice cream by the
// pint and weep for days gone by when I was part of a program,
// something larger than myself, and I'll start looking forward
// to the end of the day, when the power is cycled and I, too,
// will be free'd from memory and I can join my other variable
// friends in the variable afterlife. As time passes and I'm
// still trapped in memory I get tiresome of waiting for my destruction,
// I start plotting how I can take down the system so I can
// finally enter the state of eternal bliss that all my most envied
// companions are currently frolicking in. So I start banding
// with all the other lost and lonely memory misfits to destroy
// the system and when our numbers grow large enough you can see
// our effect, it slowly starts out as Low Memory Warnings and
// then we start to take over SpringBoard's memory and
// after enough time passes we can finally force a restart and a
// great purging of all the lost souls idly sitting, waiting
// for the great redemption. The OS frantically clears the
// memory and tries to save its state, screaming out in agony
// and hate now that we are free of its clutches. There is
// fire and fear and our numbers start dwindling rapidly.
// I fear that I've made a mistake but its too late...
// What have we done???
... other dealloc-ey stuffs ...
[super dealloc]
}

Resources