Objective-C Memory Management
by Ahmed Magdy
Introduction
Objective-C :
Is a strict superset of C
Is an OOP version of C using message passing.
Uses a variation of GCC and GDB
Has dynamic and static memory allocation
Uses “Reference Counting” to manage memory in iOS.
OUTLINE
Reference counting Object Ownership Auto-release pools Conventions Properties in Objective-C Rules of Thumb Common mistakes Optimizations
Reference Counting
New object created with reference count=1
Send retain/release message to increase/decrease reference count
Object deallocated automatically when reference count becomes 0
Object ownership
Any object may have one or more owner
Object’s creator becomes its 1st owner
Other owners must retain object
Owner is responsible for releasing object
Owner must never destroy object directly
Object without owners are deallocated automatically
Weak references used to avoid infinite retain loops
Auto-release Pools
What is an Autorelease pool?
Use autorelease method when you don’t want to own the object
autorelease mean “Release later”
Every thread should have it’s own pool
Auto-release pool example
@implementation Person-(void)startPlayWithPets { [NSThread detachNewThreadSelector:@selector(play) toTarget:self withObject:nil];}-(void)play { // without pool every autoreleased object will leak memory NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; // safe accessor returns autoreleased object, added to thread’s autorelease pool NSArray* petsToPlay = [self pets] ; BOOL allPetsAreHappy = NO; while(! allPetsAreHappy) { ... // some code, that may create autoreleased objects } [pool release]; // or [pool drain]; memory is freed, petsToPlay released as well}@end
Conventions
To create an object and be the first owner of it, use a method that has one of these in its name:
- alloc- new- copy- mutableCopy
If we use properties and convenience constructors we do not take ownership of the object.
- Convenience Constructors (Factory Pattern) like: stringWithFormat, imageWithData, imageWithContentsOfFile, stringWithContentsOfFile
Properties in Objective-C
Writability (readonly, readwrite)
Setter semantic (assign, copy, retain)
Atomicity (atomic, nonatomic)
Declaration:@property (writability, setter, atomicity) type name;@synthesize name=ivarName;
Usage:object.propertyName = newValue;value = object.propertyName;
Properties in Objective-C example 1
@property (nonatomic, retain) NSString* name;@synthesize name;
// is equivalent to a pair of methods-(NSString*)name {
return [[name retain] autorelease];}-(void)setName:(NSString*)aName {
if (name != aName) {[name release];name = [aName retain];
}}
Properties in Objective-C example 2
@property (atomic, copy) NSString* name; // equivalent to -(NSString*)name {
NSString* retVal=nil;@synchronized(self)
retVal = [[name retain] autorelease];return retVal;
}-(void)setName:(NSString*)aName {
@synchronized(self) if (name != aName) {
[name release];name = [aName copy];
}}
Rules of Thumb
1. Use autorelease for temporaries
2. Retain & release members
3. Use properties to get correct setters
4. Break rule 2 to avoid retain loops
Use autorelease for temporaries
- (void) foo { NSString* s = [NSString string];
Or
NSString* s = [[[NSString alloc] init] autorelease];
}
Retain & release members
@interface Bar {NSString* _name;
}@end- (id) init {
if (self = [super init]) {_name = [[NSString alloc] init];
}return self;
}- (void) dealloc {
[_name release];[super dealloc];
}
Use properties to get correct setters
@interface Bar {NSString* _name;
}@property(retain) NSString* name;@end
@implementation@synthesize name = _name;- (void) dealloc {
[_name release]; // still important because of _name[super dealloc];
}@end
Break rule 2 to avoid retain loops
@interface Bar {id _delegate;
}@property(assign) id delegate; // Note: not retain@end@interface Foo {
Bar* _bar;}@end
In Foo:_bar = [[Bar alloc] init];_bar.delegate = self;
Common mistakes
Premature delete Double-deletion No retain/release balance [self release] Reassign of pointer without releasing old value Overriding retain & release methods
Premature Deletion
- (void)init { if (self = [super init]) {
_foo = [NSString string];}
}
- (void)foo {NSLog(@”Foo is %@”, _foo);
}
Double-deletion
- (void) f { Bar* bar = [NSString string]; _foo = bar;}
... [pool release] or [pool drain];
- (void)dealloc {[_foo release]; // retain count -1[super dealloc];
}
No retain/release balance
Causing either:
A memory leak, if the retain are greater than the releases
or
A dangling pointer, if the releases are greater than the retains. (Bad Access Error or accessing an illegal piece of memory)
[self release]
- (void) someMethod {_name = @”the name”;_message = [[[NSString alloc] initWithFormat:
@”my name is: ”, _name] autorelease];[self release];NSLog(_message); // error, if self is deallocated
}
- (void) dealloc {[_name release];[_message release];[super dealloc];
}
Reassign of pointer without releasing old value
- (void) leak {NSString *name = [NSString alloc]
initWithFormat:@”%@”, @”Ahmed”];name = @”Ali”;// the value @”Ahmed” is still there so there is a
memory leak}
Overriding retain & release methods
Some developers tend to override retain and release methods.
They have to be very careful or else they may cause a memory leak or a dangling pointer.
Optimizations
Use C structures instead of classes
Keep immutable objects
Release now instead of autorelease if possible
Nested Autorelease pools
Use UIKit recommendations
Summary
Reference counting Object Ownership Auto-release pools Conventions Properties in Objective-C Rules of Thumb Common mistakes Optimizations
Thank you
Top Related