Tuesday, December 27, 2011

Objective-C Memory management

Introduction
When creating applications for Mac OS X, it is possible to have garbage collection enabled which means you do not need to worry about freeing memory allocated to objects. However, in iOS, due to lack of resources including CPU and memory, you cannot take advantage of a garbage collection mechanism; and  therefore, allocating and releasing objects’ memory should be handled manually.
Memory management in Objective-C is based on object ownership, where an object can have several owners; and it will exist until it loses all of its owners. If an object dose not have any owners anymore, it will be destroyed automatically by the runtime system (Memory Management Programming Guide 2011). This model is referred to as reference-counting in which all that needs to be taken care of is: keeping track of references; and when there are no references to an object, it is the runtime system responsibility to free the memory allocated to the object.
The reference-counting model works based on the following rules:
  • You are the owner of the object you create. An object is created by alloc, new, copy and mutableCopy methods. When an object is created for the first time, the reference-count for it is 1.
  • You can take ownership of an object by sending it a “retain” message. A retain message increases the reference-count by 1. You take ownership of an object to make sure you do not lose it before you are finished with it.
  • You have to release an object after you are finished with it. This is done by sending the object a release or autorelease message. Every time an object receives a release message, its reference-count decreases by 1. Figure one shows how reference-counting works.
  • You should not attempt to release an object unless you have already created or retained it.
Reference counting
Figure 1: reference-counting and object validity in Objective-C (Stevenson 2008)
Retain
One occasion that an object is sent a retain message is when the object’s value is to be stored in a property of a class. This normally happens in “setter” and “initialization” methods to prevent the property from losing its value after the referring object (the input parameter of the setter or init method) is released by its owners. Another situation to use retain is wherever an existing object’s value is going to be assigned to a secondary object; and that secondary object should exist longer than the primary object. For instance, in situations when the primary object or its parent, is going to be destroyed in other parts of the program. Finally, when assigning an object returned by a method to another object, the returning object is retained (if necessary) because its reference count may become zero after the method finished executing. 

Release
Objects should be released as soon as they are no longer needed. To do so, a release or autorelease message is sent to the object. The difference of the two messages lies in the fact that the ownership of an object, sent a release message, is relinquished immediately and in case of having no more owners, the object is destroyed and the allocated memory is freed. Whereas in autorelease, it is guaranteed that the object will exist at least until the end of the current block. Therefore, autorelease seems to be safer than release. Nevertheless, in applications that have too many objects loaded into memory, defining all the objects as autorelease can cause memory inefficiencies. There are two specific occasions that autorelease is preferred to release. First, in setters, the property is sent and autorelease before it gets the new value provided by the input parameter. Reasoning behind this is the possibility that both the property and the input parameter could point to the same location (Stevenson 2008).
- (void) setProperty: (NSObject*) inputParameter
{
    [property autorelease];
    property = [inputParameter retain];
}
The second occasion to use autorelease is when the object is supposed to be returned by the current method (Memory Management Programming Guide 2011).
- (NSString*) methodName 
{ 
    NSString* s =  [[[NSString alloc] initWithString:@”Some text”] autorelease]; 
    /*
    Some operation
    */
    return s;
}
One important point to consider is that only objects created by alloc, new, copy, or mutableCopy should be released manually. For example, an object defined as follows will not need to be sent a release or autorelease message.
NSString* s = [NSString stringWithString:@”Some text”];
In fact the definition of object “s” above is similar to the following definition:
NSString* s = [[[NSString alloc] initWithString:@”Some text”] autorelease];

Conclusion
On the whole, by following some certain rules, practical memory management in Objective-C can be none or less challenging.
  1. Using accessors, that are written based on what is discussed, to get or mutate instance variables, as having retain and release on them throughout the code makes it harder to keep their reference-count track.
  2. @property notation defines both of the accessors in a standard and safe way. All needed, is to synthesize the methods by @synthesize notation on properties.
  3. All of the instance variables should be sent their final release message in dealloc method of the class.
Complying with the rules mentioned above, memory allocated to instance variables is being managed properly. The only matter to take into account is local variables which should be explicitly released, by either release or autorelease message, whichever is appropriate based on the context, if and only if they are created using alloc method.

References

No comments:

Post a Comment