Next: Writing New Classes, Previous: The Objective-C Language, Up: Objective-C Programming Manual [Contents][Index]
Objective-C and GNUstep provide a rich object allocation and memory management framework. Objective-C affords independent memory allocation and initialization steps for objects, and GNUstep supports three alternative schemes for memory management.
Unlike most object-oriented languages, Objective-C exposes memory allocation
for objects and initialization as two separate steps. In particular, every
class provides an ’+alloc’ method for creating blank new instances.
However, initialization is carried out by an instance method, not a class
method. By convention, the default initialization method is ’-init’.
The general procedure for obtaining a newly initialized object is thus:
id newObj = [[SomeClass alloc] init];
Here, the call to alloc returns an uninitialized instance, on which
init is then invoked. (Actually, alloc does set all
instance variable memory to 0, and it initializes the special isa
variable mentioned earlier which points to the object’s class, allowing it to
respond to messages.) The alloc and init calls may be collapsed
for convenience into a single call:
id newObj = [SomeClass new];
The default implementation of new simply calls alloc and
init as above, however other actions are possible. For example,
new could be overridden to reuse an existing object and just call
init on it (skipping the alloc step). (Technically this kind of
instantiation management can be done inside init as well – it
can deallocate the receiving object and return another one in its place.
However this practice is not recommended; the new method should be
used for this instead since it avoids unnecessary memory allocation for
instances that are not used.)
In many cases you want to initialize an object with some specific information.
For example a Point object might need to be given an x, y position.
In this case the class may define additional initializers, such as:
id pt = [[Point alloc] initWithX: 1.5 Y: 2.0];
Again, a new method may be defined, though sometimes the word “new”
is not used in the name:
id pt = [Point newWithX: 1.5 Y: 2.0]; // alternative id pt = [Point pointAtX: 1.5 Y: 2.0];
In general the convention in Objective-C is to name initializers in a way that
is intuitive for their classes. Initialization is covered in more detail in
Instance Initialization. Finally, it is acceptable for an
init... method to return nil at times when insufficient memory
is available or it is passed an invalid argument; for example the argument to
the NSString method initWithContentsOfFile: may be an erroneous
file name.
Memory allocation for objects in GNUstep supports the ability to specify that memory is to be taken from a particular region of addressable memory. In the days that computer RAM was relatively limited, it was important to be able to ensure that parts of a large application that needed to interact with one another could be held in working memory at the same time, rather than swapping back and forth from disk. This could be done by specifying that particular objects were to be allocated from a particular region of memory, rather than scattered across all of memory at the whim of the operating system. The OS would then keep these objects in memory at one time, and swap them out at the same time, perhaps to make way for a separate portion of the application that operated mostly independently. (Think of a word processor that keeps structures for postscript generation for printing separate from those for managing widgets in the onscreen editor.)
With the growth of computer RAM and the increasing sophistication of memory management by operating systems, it is not as important these days to control the regions where memory is allocated from, however it may be of use in certain situations. For example, you may wish to save time by allocating memory in large chunks, then cutting off pieces yourself for object allocation. If you know you are going to be allocating large numbers of objects of a certain size, it may pay to create a zone that allocates memory in multiples of this size. The GNUstep/Objective-C mechanisms supporting memory allocation are therefore described here.
The fundamental structure describing a region of memory in GNUstep is called a
Zone, and it is represented by the NSZone struct. All
NSObject methods dealing with the allocation of memory optionally take
an NSZone argument specifying the Zone to get the memory from. For
example, in addition to the fundamental alloc method described above,
there is the allocWithZone: method:
+ (id) alloc; + (id) allocWithZone: (NSZone*)zone;
Both methods will allocate memory to hold an object, however the first one
automatically takes the memory from a default Zone (which is returned by the
NSDefaultMallocZone() function). When it is necessary to group objects
in the same area of memory, or allocate in chunks - perhaps for performance
reasons, you may create a Zone from where you would allocate those objects by
using the NSCreateZone function. This will minimise the paging
required by your application when accessing those objects frequently.
In all normal yuse however, you should confine yourself to the default zone.
Low level memory allocation is performed by the NSAllocateObject()
function. This is rarely used but available when you require more advanced
control or performance. This function is called by [NSObject
+allocWithZone:]. However, if you call NSAllocateObject() directly to
create an instance of a class you did not write, you may break some
functionality of that class, such as caching of frequently used objects.
Other NSObject methods besides alloc that may optionally take
Zones include -copy and -mutableCopy. For 95% of cases you
will probably not need to worry about Zones at all; unless performance is
critical, you can just use the methods without zone arguments, that take the
default zone.
Objects should be deallocated from memory when they are no longer needed.
While there are several alternative schemes for managing this process (see
next section), they all eventually resort to calling the NSObject
method -dealloc, which is more or less the opposite of -alloc.
It returns the memory occupied by the object to the Zone from which it was
originally allocated. The NSObject implementation of the method
deallocates only instance variables. Additional allocated, unshared memory
used by the object must be deallocated separately. Other entities that depend
solely on the deallocated receiver, including complete objects, must also be
deallocated separately. Usually this is done by subclasses overriding
-dealloc (see Instance Deallocation).
As with alloc, the underlying implementation utilizes a function
(NSDeallocateObject()) that can be used by your code if you know what
you are doing.
In an object-oriented environment, ensuring that all memory is freed when it is no longer needed can be a challenge. To assist in this regard, there are three alternative forms of memory management available in Objective-C:
alloc, copy etc, and deallocate
them when you have finished with them (using dealloc).
This gives you complete control over memory management, and is highly
efficient, but error prone.
The recommended approach is to use some standard macros defined in
NSObject.h which encapsulate the retain/release/autorelease mechanism,
but which permit efficient use of the garbage collection system if you build
your software with that. We will justify this recommendation after describing
the three alternatives in greater detail.
This is the standard route to memory management taken in C and C++ programs.
As in standard C when using malloc, or in C++ when using new and
delete, you need to keep track of every object created through an
alloc call and destroy it by use of dealloc when it is no longer
needed. You must make sure to no longer reference deallocated objects;