Memory Management in Objective-C
Pages: 1, 2, 3
autorelease
Another way we can decrease an object's reference count is by sending it an autorelease message. When you send an autorelease message, the receiver is not immediately freed from memory, as is the case with release. Rather, autorelease decreases the receiver's reference count by one at some point in the future. autorelease thus provides added flexibility when releasing an object and lets us use it a little bit longer before it is actually de-allocated.
autorelease works by making use of an object known as an "autorelease pool." Whenever you send an object an autorelease message, it is added to the autorelease pool. At the end of the event loop, this autorelease pool is released by the application object and then all of the objects contained within it are released. At the beginning of the next loop, a new pool is created and the process is repeated ad infinitum. For practical purposes, an autoreleased object is considered to be valid anywhere within the scope where it received the autorelease message.
For example, our button method from MemApp can be changed to incorporate autorelease, rather than release.
- (IBAction)goButton(id)sender
{
AClass *ourObject;
ourObject = [AClass alloc];
[ourObject autorelease];
// We can still use ourObject until
// the very end of this method!
}
When we run this code through ObjectAlloc, we find that the instance counts are exactly the same as we got before with release. This shouldn't surprise you because the object is released after the end of the method.
autorelease is especially useful when we have a method that creates and returns an object. In this situation, if we follow the rules, we have to make sure any object we create is destroyed before it's too late. Using release in this case won't work because the object we're trying to return will be destroyed before it can be returned.
- (NSString)releasedString
{
NSString *string = [[NSString alloc] initWithString:@"The Sender of this message will never see this string…"];
[string release]; // we have to do this or we'll get a memory leak
return string; // but what are we returning?
}
The solution to this is to use autorelease which allows us to properly deal with objects that we create and own, while giving the sender of the message a chance to grab onto the returned object for its own use.
- (NSString)autoreleasedString
{
NSString *string = [[NSString alloc] initWithString:@"The Sender of this message will never see this string…"];
[string autorelease]; // we have to do this or we'll get a memory leak
return string;
}
We can now return a string to the message sender and let our minds rest comfortably knowing that we've fulfilled our duty to prevent memory leaks. These last few examples provide a perfect place to jump into our next topic -- convenience constructors -- which fit into the mold of a method that creates and returns an autoreleased object.
Convenience constructors
By now you have probably noticed in the class documentation that most Cocoa classes have a set of class methods that are named in the format +className.... These special class methods are called "convenience constructors," and are used to create temporary objects. What I mean by temporary is that objects returned by a convenience constructor are assumed to be autoreleased, and are thus valid only within the method that uses the convenience constructor.
An example of one of the many convenience constructors available is the NSString method, +stringWithCString:. We can use this method instead of creating an NSString instance using the usual alloc/init process. For example, consider the following code that uses alloc and init:
NSString *string = [[NSString alloc] initWithCString:"Hello"];
[textField setStringValue:string];
[string release];
This can be shortened using a convenience constructor:
NSString *string = [NSString stringWithCString:"Hello"];
[textField setStringValue:string];
// don't need to release string since objects
// returned by convenience constructors are
// assumed to be autoreleased.
Convenience constructors also make it less cumbersome to nest messages:
[textField setStringValue:[NSString stringWithCString:"Hello]];
So, if you need a string (or any other object) to exist only within a method, it's often easier, cleaner, and more readable to use a convenience constructor.
If you want to set an instance variable using a convenience constructor, you have to send it a retain message so that it is not released when the autorelease pool is cleared out, like so:
// assume stringInstanceVariable exists
stringInstanceVariable = [[NSString stringWithCString:"Hello"] retain];
retain is a way to assess object ownership on objects that you didn't initially create, so this extends our rule of matching every alloc with a release or autorelease, and now we also have to match any retain messages with release or autorelease.
Find out more about memory management
In this column I have tried to cover the basics of memory management in Cocoa and Objective-C. There are several other excellent articles and references available that I strongly encourage you to read. These articles go into more detail, provide additional code examples, and cover various "traps" that you have to look out for. Below is a list of these references:
Very Simple Rules for Memory Management in Cocoa by mmalcolm crawford provides a good summary of what we have discussed here, including several examples that show how to avoid memory leaks in your code.
Hold Me, Use Me, Free Me by Don Yacktman is a detailed overview of the problem of memory management and how it is handled in Cocoa and Objective-C.
Object-Oriented Programming and The Objective-C Language, Chapter 6, "Object Ownership and Automatic Disposal" from Apple. Anyone serious about learning Cocoa should read this book. Editions of this book published after December 2000 contain the chapter about memory management. This book covers many of the same things we talk about here, but comes straight from the developers at Apple. It also emphasizes the idea of object ownership. You can never have too many references!
Class references for NSObject and NSAutoreleasePool can be found on the Apple web site. The methods
+alloc,-release,-retain, and-autoreleaseare all defined and described here. TheNSAutoreleasePoolreference goes into more detail regarding the operation of autorelease pools, and includes a description about how you can create your own autorelease pools, and when you might want to do so.
Well, that's it for now for memory management. I hope I have given you a good feeling for how reference counting and memory management works in Objective-C and Cocoa. If you're still a bit shaky, don't worry too much. In the next several columns we will be building an application where we will follow the rules of good memory management, so you will be able to see how we implement all of this in real code. In the next article, we will build the interface for this application and learn a few things about tables in interfaces and the NSTableView class.
Michael Beam is a software engineer in the energy industry specializing in seismic application development on Linux with C++ and Qt. He lives in Houston, Texas with his wife and son.
Read more Programming With Cocoa columns.
Return to the Mac DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 18 of 18.
-
Stack objects
2003-03-06 15:54:34 anonymous2 [Reply | View]
Since Objective C doesn’t use implicit constructors and destructors the was C++ does, what are the implications for creating an object on the stack? Is it simply a matter of sending the object an init message, or are there hidden issues here?
-
Finally got it!
2002-07-19 03:15:35 hgegenfurtner [Reply | View]
After reading this column, I finally understand what this "autorelease" and "retain" is about. Thanks again, Mike, as well as for the links to the other articles concerning memory management.
This is an excellent Cocoa tutorial
(except for the many typos ...)
-
Tendentious (if not outrightly erroneous) comparison of (manual) Reference counting and Automatic garbage collection
2001-08-10 11:29:51 bparsia1 [Reply | View]
You wrote:
"Java, for instance, implements a memory management system known as automatic garbage collection. In this system, the developer does not need to worry about actively de-allocating unused objects, rather a hidden garbage collector checks each object to see whether or not it is being used by other objects...."
The use of "hidden" is quite misleading. In most GCed systems (I don't know Java, so if this is a Java specific point...well, so much the worse for Java), garbage collection can be explicitly triggered (e.g., in Squeak by "Smalltalk garbageCollect.") and high end Smalltalk and Common Lisp systems (for example) there are lots of aspects of the GC which are exposed to the programmer for tuning purposes (e.g., you can adjust the size of various spaces, put some objects in a non-scanned "permanant" space, or even change the entire GC strategy).
Then you wrote:
"Objective-C uses another form of memory management known as "reference counting." In this system, each object is associated with a count of how many other objects are currently using it, but the reference counts of objects in an application must be actively managed by the developer."
To be accurate this is *manual* reference counting. It's perfectly possible to use a reference counting strategy as an *automatic garbage collection* technique. Perl and Python do this. RC and automation are orthoganal issues.
Then you wrote:
"Both of these memory management schemes have advantages and disadvantages. Automatic garbage collection is easy on the developer because it's entirely automatic. However, this convenience comes at the expense of performance and efficiency."
This is highly tendentious at best. GC strategies (and their implementation) vary widely in their performance characteristics and how well they do often depends *a lot* on the application in question. *Lifetime* costs to an application run for a stop and copy collector can be very low (although there might be undesirable effects, like long pauses...these are undesirable for (many) *interactive* programs, but might be quite reasonable for a scientific modeling program where overall time saved is more important than avoiding pauses). Furthermore, different collection strategies enable different (often more efficient) allocation strategies, or can help locality, etc. etc.
A naive RC (manual or otherwise) can perform *way* worse. One simple example is if your code contains lots of cyclic data structures. Or if the references to many of your objects fluctuates rapidly (so your ref counts are constantly and pointlessly being altered).
Now there are clever ways around this, but they have their tradeoffs as well.
Finally:
"Reference counting on the the hand is very efficient and fast because there is no garbage collector working behind the scenes using up resources."
I take it that the above points amply demostrate how silly this is.
For futher reading I recommend the following:
Paul Wilson's large GC survey: http://www.cs.utexas.edu/users/oops/papers.html#bigsurv
Richard Jones' book and list of links: http://www.cs.ukc.ac.uk/people/staff/rej/gc.html
Or just do some simple research. Googling about will help.
There were some neat discussion of RC vs. other strategies on comp.lang.lisp. For example:
http://groups.google.com/groups?q=lisp+reference+counting&hl=en&safe=off&rnum=5&selm=3afc0ba5.14780192%40news.callatg.com:
and:
http://groups.google.com/groups?hl=en&safe=off&th=76b4e5f2702d873,33&start=10
Really, that whole thread.
Now, RC strategies of various sorts *do* have interesting properties that can be useful in various situtations, but it's irresponsible to pass on the "convenience vs. performance" myth. The grounds for deciding are *far* more complicated.
-
(Q) interchangeable pointers and objects
2001-07-30 20:30:20 psheldon [Reply | View]
Toward the end of the last page, Mike Beam writes "Convenience constructors also make it less cumbersome to nest messages". I noted something puzzling here that I also vaguely remember from another object oriented language, Apple's object oriented pascal course I took long ago.
Note above this sentence on nesting that the variable string points to a NSString, the star prefix on string is saying the thing pointed to by the variable string is an NSString type. The method setStringValue accepts this pointer. But, when we collapse things into a nest, it accepts, not a pointer to, but rather the NSString type itself.
I might windily say that "the compiler is smart enough to forgive" or "the language is not context free in interpretation", but I think there is something deeper going on that makes all object oriented languages "forgive" this way, that this is "a feature and not a bug", a feature I might better exploit if I don't simply rationalize away with these windy words, but put into some sort of new rules for my writing code, rules to not merely rationalize what I have seen but also predict and help me write code I haven't seen.
Perhaps there is an introductory remark somewhere, something toward these rules, so I will more fearlessly let the compiler forgive me and not fuss with such things. -
Object Semantics
2001-07-31 07:29:27 canyonrat [Reply | View]
I think it's dangerous to generalize here. You just have to accept that ObjC is an OO language that uses pointer semantics and move on. Object Pascal also uses pointer semantics but Java uses reference semantics and C++ uses copy semantics.
All these languages are dealing with the same question: "How do I return an object from a method that will remain valid when the method goes out of scope?"
C++ takes the most straightforward approach and copies the object. There is no behind the scenes conversion from myType to myType*. This puts the burden on the programmer of defining a copy constructor for all but the most trivial classes. It also can really bog a program down in copying.
Java attempts to solve the problem with a universal garbage collector. At least in 1.2 it didn't really work and for a serious program the programmer had to manage memory "by hand." It may be fixed now.
ObjC does return a myType* and asks the programmer to autorelease it or to make it with a convenience constructor that shifts memory management duties to the class object. -
Object Semantics
2001-07-31 10:42:35 psheldon [Reply | View]
I am enjoying Cocoa introduced to me by Mike Beam. I thank you for your responses to my question.
To show kindness and gratitude, I think I should stick my neck out actively responding to your responses and try to tell how they helped me focus.
I shall give you three prefatory examples :
Once I knew a computer science major who constantly asked the question is this a pass by reference or pass by value. It seemed to him a fundamental question that would clarify his understanding of code. What was the meaning or semantics of that old equal sign.
In optical holography I saw two images called equal if they had transmission fields that were proportional. Once I knew there was a semantics to the symbol equal that was held in the "folklore of the subject", things became a whole lot easier to read and write.
Maple allows assignment of expressions to variables and has complex rules of whether to take final evaluations or intermediate evaluations for procedures that I yet need to learn to use profitably. Not that I don't think this complexity useful, rather I don't yet know how to be useful with it.
Some more introductory remarks to try to tell that I am coming from somewhere safe:
When you have gotten to the point of thinking in a language, things aren't explicitly written down in any publication or textbook, but rather in this "folklore of the subject". The guys who write the insides of a language or compiler know stuff users don't and probably in a folklorish sort of way. They are not ready to share this, either because it will scare off users or just because it hasn't gotten "that perfect" yet.
The semantic debates between language and compiler designers might, in fact, be blessedly hidden. Nonetheless, these debates happened. The big boys argued, each thought he won and the lesser of us might hide in one big boys house or the others. Whether the hiders or the big boys have ahold of the greater truth might be questioned. One can learn a lot playing a game for a little while rather than merely practicing running things into the ground with high level debate. There are also more choices of how to be than these two; I can choose to believe this.
My search for threads to make things coherent :
You (CanyonRat) mentioned "pointer semantics" which told me the words in that formal presentation that I wanted. That was very reassuring.
So, I sherlock 2 searched those words and sped read a bunch of threads :
http://www.rt.mipt.ru/docs/oop/chap12/study.htm
and reassuringly found my question, "What does it mean to say a programming language uses pointer semantics for assignment? ", a study question for a text on general object oriented programming.
Then, I sherlock 2'd again :
http://vip.cs.utsa.edu/classes/cs4773s97/classes/cs4773.topic20.html
"There are three possible interpretations of assignment
...
Pointer semantics: Assignment changes the reference of the left side to be the right side.
Also called pointer assignment
The two variables not only have the same value but also refer to the same object. "
All that reassures me from this statement is that the meaning (semantics) of the equal sign in an assignment varies in different languages.
Now, from my thread experience, I attempt to stretch my imagination (do the homework, pay my dues) to try to see pointer semantics might mean equal sign semantics (meaning).
Suppose there were a language that only passed or assigned by pointer semantics, then the compiler might look to see if a parameter were already a pointer or autoconvert to a pointer for assignments within a method (I believe what you call "behind the scenes conversion from myType to myType*."). I saw some debate in these threads about whether autoconversion was a good thing or could have you pointing to something that wasn't there and this was debate about language design involving tradeoffs of release pools vs other ways of freeing memory (beyond my caliber). That it was debated indicated that it was considered.
Thence, I believe, you write "You just have to accept that ObjC is an OO language that uses pointer semantics and move on". Indeed, I don't wish to debate semantics or which language is best I am not of that caliber. I want to get just a "feel" of the axioms of Cocoa, but can't demand axiomatic definition or be pleased if someone gave it to me (I probably would get confused). Right now I can want to go on and code and dirty my hands. Indeed, as Justin Armstrong wrote, "...spend a while looking at it, ObjC takes some getting used to, but is in fact entirely sensible!" (well I'm not sensible, yet, and wish I could get more sensible as painlessly as possible).
;-)
I am sorry that I don't have the axiomatic base or feel to write tersely as you do. For example, your "All these languages are dealing with the same question: "How do I return an object from a method that will remain valid when the method goes out of scope?"" Languages are candidate solutions to my question, oh boy. Have I asked a question whose answer is beyond my caliber to appreciate?
I think somewhere in the book objective C is a caveat that there is no EBNF or grammar representation for objective C yet, it's in the "folklore" we are sharing now and you guys are sharing a more distilled version than I.
Thank you, I feel a little wiser but am still hungry as I am not entirely sensible, yet.
;-)
I have learned that when I do homework things always get more confused before they get simpler. I don't know whether I should have done homework in open forum because of this, yet I felt I should aknowledge response publically and gratefully.
I hope you see I am human and don't bite.
Maybe someone will be able to say the threads I found above in a more distilled fashion than I did and I shall be happier.
-
Where is the folklore
2001-08-01 20:54:55 canyonrat [Reply | View]
ObjC hasn't really been used by enough people for long enough to have its folklore published yet. That's OK. The books that capture the spirit and the conventions of any development system are distilled from news groups and mailing lists. You can always go to the source.
Stroustrup suggests that if you are seriously using any language, you should subscribe to at least two news groups/mailing lists dedicated to it. I think that's good advice.
For ObjC the best candidates seem to be:
cocoa-dev@lists.apple.com
and
macosx-dev@omnigroup.com
You can learn a lot just lurking. But do ask questions. The folks are friendly and helpful.
-
Where is the folklore
2001-08-02 14:21:24 psheldon [Reply | View]
Thank you. I am very curious about these candidates, especially omnigroup's. They were involved in os x translations of the game quake and have uncommented game frameworks.
I really like the newsgroup thread structure so that I would not appear intrusive and also could choose what to read . Do these have thread structure ?
From superficially looking at them being e mail addresses I write to, I am sorry that cocoa-dev@lists.apple.com and macosx-dev@omnigroup.com don't seem to have this thread structure.
Perhaps, however, I write these e mail addresses to join the list ? Yet I might like to see that the lists supply a thread structure.
Do e mails there work like yahoo e groups and appear on a web page like this forum with threads.
Do they put my on some sort of local-computer group list for my news reader (newswatcher, incidentally).
Looking at my isp's group list, I searched objective and found objective c.
comp.lang.objective-c
This was the only newswatcher group I found that seemed relevant.
-
cocoa-dev with browser-nomail option
2001-08-02 21:24:14 psheldon [Reply | View]
In the FAQ about the list that the e mail address, cocoa-dev@lists.apple.com, writes to, Apple indicates you can have a nomail option.
http://www.lists.apple.com/cgi-bin/mwf/topic_show.pl?id=46
Apple's list further offers other less intrusive mail options such as receive digest once a day rather than individual mails.
FAQ also indicated people actually didn't want to use newsservers :
http://www.lists.apple.com/cgi-bin/mwf/topic_show.pl?id=47
Apple writes :
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
"The archives are not currently searchable. We're working on adding a search engine to the archives, but don't yet have a date that it'll be functional. "
so the list only has "human memory" now.
I am ever curious about Apple's knowledge navigation improvements. -
Where is the folklore
2001-08-02 20:46:40 canyonrat [Reply | View]
I should have given the web address of those lists. Cocoa-dev is at:
http://lists.apple.com/mailman/listinfo/cocoa-dev
macosx-dev is at:
http://www.omnigroup.com/community/developer/mailinglists/macosx-dev/
Threading is really done in the reader and it's easier to thread a news group than a mailing lit so many mailers don't thread. I tend to use Entourage because it threads both news groups and mailing lists.
If you don't have a threading mail program, both of the above lists let you read threads on the web.
comp.lang.objective-c has some good discussions but it's more oriented to people porting and extending the ObjC language and not just to Mac programmers. -
thanks, checked omnigroup (nomail?)
2001-08-02 21:40:48 psheldon [Reply | View]
Interesting that you can have a threading mail program, but more interesting is that the list can observe threads in archives through a browser.
Since I couldn't find the FAQ, I want to ask confirmation does omnigroup have a nomail option as well? -
(Q) interchangeable pointers and objects
2001-07-31 07:23:03 justinarmstrong [Reply | View]
is this the line that is confusing you?
[textField setStringValue:[NSString stringWithCString:"Hello"]];
remember how the square brackets show
the nesting of message sends.
the first message sent is 'stringWithCString:'
which goes to the NSString *class* object.
A class object is a special kind of object
that knows how to create other objects,
in this case instances of NSString.
So, as a result of this stringWithCString
message is a new NSString instance that
in this case contains the text "Hello".
This new string is then passed as an
argument to the setStringValue: message
which is sent to a textField.
there isn't really any voodoo compiler
stuff going on behind your back.
"NSString" is just the name of a global
object that happens to be a class object.
if you look at
NSString* string = [NSString stringWithCString:"hello"];
this creates a variable called 'string'
which is a pointer to an instance of
'NSString'. This pointer is then initialized
to a new instance of the class NSString.
spend a while looking at it, ObjC takes
some getting used to, but is in fact entirely
sensible!
-
(Q) interchangeable pointers and objects
2003-12-09 17:35:27 anonymous2 [Reply | View]
If you want to gain a better understanding of the relationship between a class and its instances, and find out what is happening "behind the scenes," I suggest you read the article below.
http://www.macdevcenter.com/lpt/a/2432
It takes careful reading, but is very valuable. Keep in mind that all objective-c objects are manipulated as pointers to an object that exists somewhere else in memory--the id type is implemented as a pointer to a class or instance. Classes are also objects. This is why a message can be sent to a class, as in the NSString initialization example. In [NSString stringWithCString:"hello"], NSString is actually a pointer to the object representing the NSString class, not to the NSString type. (I conjecture that the NSString type is actually not a type but a struct--structs behave somewhat like a typedef under certain circumstances). Maybe I've clarified things, or maybe I've just written an incomprehensible bunch of jargon. I can't tell. If this helps, good. If not, ignore it.
-
Really good treatment
2001-07-28 09:55:23 canyonrat [Reply | View]
This is a very good intro to a complex subject. I just wish the article were longer. Retain vs copy might be a good subject for a follow-up piece. -
Really good treatment
2001-07-28 19:50:32 chaoswerks [Reply | View]
Here's a simple guide for retain or copy. Use retain when the object represents a relationship. Use copy when the object represents a value. The difference is this: in a relationship, if the object pointed to changes, you want your variable to reflect this change of state; whereas, with a value, you want the value to remain unaltered if the original object changes unless you explicitly alter your copy.






Open your project file in xcode and responded "Upgrade a Copy." Made the following changes to Controller.m.
#import "Controller.h"
@implementation Controller
- (IBAction)goButton:(id)sender
{
AClass *ourObject;
ourObject = [AClass alloc];
// do stuff with ourObject
[ourObject release];
ourObject=nil;
}
@end
Rebuilt in xcode.
Found ObjectAlloc on my system where you said it would be. Ran it. From the File->Run menu, selected MemApp/Build/MemApp.app and started it in ObjectAlloc.
My difficulty is that AClass shows this:
Current: 4
Peak: 4
Total: 4
I see no evidence of "releasing." Anyone else experience this behavior.
Mac os x 10.4.10 and xcode 2.4.1 and ObjectAlloc 3.4.
Thanks.