Memory
Leaks

Modified

Downloads

Leaky1 example

Leaky2 example

Overview

Xcode provides tools for monitoring memory use and detecting some memory leaks. The following provides some guidance to using Xcode.

Leaky1

  1. Download and open the Leaky1 example.
     
  2. Open the LeakTest directory and LeakTest.xcodeproj.
     
  3. LeakTestViewController.m
    #import "LeakTestViewController.h"
    
    @interface Leaky: NSObject {}
    -(void) print;
    @end
    
    @implementation Leaky
    
    -(void) print {
    	NSLog(@"Leaky print\n");
    }
    
    - (void)dealloc {
        [super dealloc];
        NSLog(@"Leaky dealloc\n");
    }
    @end
    
    @implementation LeakTestViewController
    
    -(IBAction) click: (id) sender {
    Leaky *l = [Leaky alloc];
           [l print];
    //   [l release];
    }
    @end
  4. In Xcode, to statically detect leaks:

    Build | Build and Analyze

    You should be rewarded with a potential leak.

  5. Instruments executes and monitors resources used by an app. To monitor memory usage and detect run-time leaks:

    Run | Run with Performance Tool | Leaks
     

  6. In Instruments, click the Leaks icon.

    Set Sampling Options to 1.0

    Open the Simulator and click the button a few times.

    You should see something similar to below.

  7. The above shows that the object Leaky was allocated but not released.

    Question - 16 bytes per allocation - why?
     

  8. To monitor all allocations, click the Allocations icon.

    Scroll down to locate Leaky allocations - 4 allocations are currently living.

Fixing leaks

The leak pointed out by Build and Analyze can be plugged by releasing the allocated object as below.

LeakTestViewController.m
#import "LeakTestViewController.h"

@interface Leaky: NSObject {}
-(void) print;
@end

@implementation Leaky

-(void) print {
	NSLog(@"Leaky print\n");
}

- (void)dealloc {
    [super dealloc];
    NSLog(@"Leaky dealloc\n");
}
@end

@implementation LeakTestViewController

-(IBAction) click: (id) sender {
       Leaky *l = [Leaky alloc];
       [l print];
[l release];
}
@end
  1. Remove the comment on [ l release ];
     
  2. Repeat the static analysis:

    Build | Build and Analyze

    There should be no leaks detected.
     

  3. Test again for dynamic leaks by:

    Run | Run with Performance Tool | Leaks

    In the Simulator, click the button a few times. No leaks should be detected and Leaky allocations should be 0.
     

Deallocation

When an object reference count is 0 the object's dealloc method is called.

LeakTestViewController.m
#import "LeakTestViewController.h"

@interface Leaky: NSObject {}
-(void) print;
@end

@implementation Leaky

-(void) print {
	NSLog(@"Leaky print\n");
}
- (void)dealloc {
    [super dealloc];
    NSLog(@"Leaky dealloc\n");
}
@end

@implementation LeakTestViewController

-(IBAction) click: (id) sender {
       Leaky *l = [Leaky alloc];
       [l print];
      [l release];
}
@end

After clicking the Click button a few times, to see the NSLog output:

Run | Console

Over-deallocating

Releasing an object that no longer exist crashes the application.

  1. Add another [ l release ]
     
  2. Build and Run
     
  3. Click
     
  4. Run | Console

    Question - Can you explain what happened?

LeakTestViewController.m
#import "LeakTestViewController.h"

@interface Leaky: NSObject {}
-(void) print;
@end

@implementation Leaky

-(void) print {
	NSLog(@"Leaky print\n");
}

- (void)dealloc {
    [super dealloc];
    NSLog(@"Leaky dealloc\n");
}

@end

@implementation LeakTestViewController

-(IBAction) click: (id) sender {
       Leaky *l = [Leaky alloc];
       [l print];
       [l release];
[l release];
}
@end

 

Leaky2

To more closely observe alloc and release operations.

  1. Download and open the Leaky2 example.
     
  2. Open the LeakTest directory and LeakTest.xcodeproj.
     
  3. LeakTestViewController.m
    #import "LeakTestViewController.h"
    
    @interface Leaky: NSObject {}
    -(void) print;
    @end
    
    @implementation Leaky
    
    -(void) print {
    	NSLog(@"Leaky print\n");
    }
    
    - (void)dealloc {
        [super dealloc];
    	NSLog(@"Leaky dealloc\n");
    }
    
    @end
    
    @implementation LeakTestViewController
    
    Leaky * l;
    
    -(IBAction) allocLeaky: (id) sender {
    				
            l = [Leaky alloc];
    [l print]; } -(IBAction) releaseLeaky: (id) sender {
            [l release];
    } @end
  4. In Xcode, to statically detect leaks:

    Build | Build and Analyze

    With alloc and release in separate methods, it fails to detect a potential leak.

     

  5. Monitor memory usage and detect run-time leaks:

    Run | Run with Performance Tool | Leaks
     

  6. In Instruments, click the Leaks icon.

    Set Sampling Options to 1.0

    Open the Simulator and click allocLeaky button once.

    Question - Why no leaks?

    Click allocLeaky button once. Question - What happens and why?

    Question - You should see something similar to below after how many clicks?

  7. The above shows that the object Leaky was allocated but not released.
     
  8. As long as the number of alloc and release match, no problems. Question - Right?
     

Over-deallocating

  1. Stop recording and start again.
     
  2. Click releaseLeaky once. Question - What results?
     
  3. Question - What should happen if clicked again?
     
  4. In Xcode

    Build and Run

    Run | Console

allocLeaky 4 times.

releaseLeaky 2 times.

Question - Explain what happened and why.

LeakTestViewController.m
#import "LeakTestViewController.h"

@interface Leaky: NSObject {}
-(void) print;
@end

@implementation Leaky

-(void) print {
	NSLog(@"Leaky print\n");
}

- (void)dealloc {
    [super dealloc];
	NSLog(@"Leaky dealloc\n");
}

@end

@implementation LeakTestViewController

Leaky * l;

-(IBAction) allocLeaky: (id) sender {
				
        l = [Leaky alloc];
        [l print]; } -(IBAction) releaseLeaky: (id) sender {
        [l release];
} @end