fixing memory issues

Upload: subhapam-kundu

Post on 10-Oct-2015

43 views

Category:

Documents


0 download

DESCRIPTION

Fixing Memory issues in iOS

TRANSCRIPT

  • These are confidential sessionsplease refrain from streaming, blogging, or taking pictures

    iOS and OS X techniques

    Session 410

    Fixing Memory Issues

    Kate StoneSoftware Behavioralist

    Daniel DelwoodSoftware Radiologist

  • Time

    Poor user experience

  • Time

    Lack ofresources

    Poor user experience

  • Time

    Bugs

    Lack ofresources

    Poor user experience

  • Agenda

    Overview of app memoryHeap memory issuesObjective-C, retain/release Being a good citizen

  • Measurement and fundamentalsOverview of App Memory

  • Xcode GaugesMemory at a glance

  • Xcode GaugesMemory at a glance

  • Xcode GaugesMemory at a glance

  • Instruments focused on allocation heap

    Memory: the Big Picture

    Your Process

    Heap

  • Instruments focused on allocation heap Processes contain more than just heap memory

    Application code Images and other media

    Memory: the Big Picture

    Your Process

    Heap

  • Instruments focused on allocation heap Processes contain more than just heap memory

    Application code Images and other media

    Memory: the Big Picture

    Your Process

    ?Heap

  • Instruments focused on allocation heap Processes contain more than just heap memory

    Application code Images and other media

    Measurements depend on what you are measuring and how

    Memory: the Big Picture

    Your Process

    ?Heap

  • DemoXcode to instruments memory tools

  • Allocations and Virtual Memory

    Familiar instrument with a twist Backtraces for VM region activity Call trees for all allocations Efficient alternative: VM only

    Exposes previously hidden details Who mapped a file? What non-heap memory contributes to my footprint?

    Page-level statistics Snapshot using VM Tracker instrument

  • Allocations and Virtual Memory

    Familiar instrument with a twist Backtraces for VM region activity Call trees for all allocations Efficient alternative: VM only

    Exposes previously hidden details Who mapped a file? What non-heap memory contributes to my footprint?

    Page-level statistics Snapshot using VM Tracker instrument

  • Allocations and Virtual Memory

    Familiar instrument with a twist Backtraces for VM region activity Call trees for all allocations Efficient alternative: VM only

    Exposes previously hidden details Who mapped a file? What non-heap memory contributes to my footprint?

    Page-level statistics Snapshot using VM Tracker instrument

  • Allocations and Virtual Memory

    Familiar instrument with a twist Backtraces for VM region activity Call trees for all allocations Efficient alternative: VM only

    Exposes previously hidden details Who mapped a file? What non-heap memory contributes to my footprint?

  • Allocations and Virtual Memory

    Familiar instrument with a twist Backtraces for VM region activity Call trees for all allocations Efficient alternative: VM only

    Exposes previously hidden details Who mapped a file? What non-heap memory contributes to my footprint?

    Page-level statistics Snapshot using VM Tracker instrument

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty Private vs. Shared

    Virtual Memory

  • Key concepts

    Virtual vs. Resident Virtual memory reserved as regions

    4KB page aligned Pages mapped to physical memory on first read/write

    Zero-filled or read from storage Once mapped, virtual memory is also resident

    Physical memory typically more constrained

    Virtual Memory

    Physical Memory

    Virtual Address SpaceRegion Region

  • Key concepts

    Virtual vs. Resident Virtual memory reserved as regions

    4KB page aligned Pages mapped to physical memory on first read/write

    Zero-filled or read from storage Once mapped, virtual memory is also resident

    Physical memory typically more constrained

    Virtual Memory

    Physical Memory

    Virtual Address Space

    Page

    Region Region

  • Key concepts

    Virtual vs. Resident Virtual memory reserved as regions

    4KB page aligned Pages mapped to physical memory on first read/write

    Zero-filled or read from storage Once mapped, virtual memory is also resident

    Physical memory typically more constrained

    Virtual Memory

    Physical Memory

    Virtual Address Space

    Page Page

    Region Region

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty

    Clean pages can be discarded and recreated Memory mapped files, executable __TEXT segments, purgeable memory

    Changing a page marks it as dirty Malloc heap, global variables, stacks, etc. Can be swapped to compressed form or storage on OS X

    Virtual Memory

    Physical Memory

    Virtual Address Space

    Page

    Region

    Swap SpacePage

    Region

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty

    Clean pages can be discarded and recreated Memory mapped files, executable __TEXT segments, purgeable memory

    Changing a page marks it as dirty Malloc heap, global variables, stacks, etc. Can be swapped to compressed form or storage on OS X

    Virtual Memory

    Physical Memory

    Virtual Address Space

    Page

    Region

    Swap SpacePage

    Region

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty Private vs. Shared

    Virtual memory can be named to enable sharing Mapped files are implicitly shareable

    Virtual Memory

    Virtual Address Space

    Physical Memory

    Region Region

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty Private vs. Shared

    Virtual memory can be named to enable sharing Mapped files are implicitly shareable

    Virtual Memory

    Virtual Address Space

    Physical MemoryPage

    Region Region

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty Private vs. Shared

    Virtual memory can be named to enable sharing Mapped files are implicitly shareable

    Virtual Memory

    Virtual Address Space

    Physical MemoryPage Page

    Region Region

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty Private vs. Shared

    Virtual memory can be named to enable sharing Mapped files are implicitly shareable

    Virtual Memory

    Virtual Address Space

    Physical MemoryPage Page

    Region Region

    Virtual Address SpaceRegion Region

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty Private vs. Shared

    Virtual memory can be named to enable sharing Mapped files are implicitly shareable

    Virtual Memory

    Virtual Address Space

    Physical MemoryPage Page

    Region Region

    Virtual Address SpaceRegion Region

  • Key concepts

    Virtual vs. Resident Clean vs. Dirty Private vs. Shared

    Virtual memory can be named to enable sharing Mapped files are implicitly shareable

    Virtual Memory

    Virtual Address Space

    Physical MemoryPage Page Page

    Region Region

    Virtual Address SpaceRegion Region

  • Tools and tacticsHeap Memory Issues

  • Storage for malloc() callsWhat is the Heap?

    Dynamic allocations using malloc or variants malloc in C [NSObject alloc] in Objective-C new operators in C++

    Allocated directly or indirectly through framework API Backed by VM: MALLOC regions

  • Expensive Types Investigating the Heap

    VM is about bytes, heap is about counts

  • Expensive Types Investigating the Heap

    VM is about bytes, heap is about counts Small object can have a large graph

  • Expensive Types Investigating the Heap

    VM is about bytes, heap is about counts Small object can have a large graph

    UIView96 bytes

  • Expensive Types Investigating the Heap

    VM is about bytes, heap is about counts Small object can have a large graph

    UIView96 bytes layer

    viewDelegate

    subviewCache

    gestureRecognizers

  • Expensive Types Investigating the Heap

    VM is about bytes, heap is about counts Small object can have a large graph

    UIView96 bytes

    CALayer32 byteslayer

    viewDelegate

    subviewCache

    gestureRecognizers

  • Expensive Types Investigating the Heap

    VM is about bytes, heap is about counts Small object can have a large graph

    UIView96 bytes

    CALayer32 byteslayer

    viewDelegate

    subviewCache

    gestureRecognizers

    layer

    Bitmap DataVM Region

  • Expensive Types Investigating the Heap

    VM is about bytes, heap is about counts Small object can have a large graphObvious containers: NSSet, NSDictionary, NSArray,

    UIView96 bytes

    CALayer32 byteslayer

    viewDelegate

    subviewCache

    gestureRecognizers

    layer

    Bitmap DataVM Region

  • Expensive Types Investigating the Heap

    VM is about bytes, heap is about counts Small object can have a large graphObvious containers: NSSet, NSDictionary, NSArray, Less obvious: UIView, UIViewController, NSImage,

    UIView96 bytes

    CALayer32 byteslayer

    viewDelegate

    subviewCache

    gestureRecognizers

    layer

    Bitmap DataVM Region

  • Your classes! Prefixes are helpful (e.g. ABCViewController)

    New type identifications Better at C++ classes dispatch and xpc types Heap-copied ^blocks (__NSMallocBlock__)

    Investigating the Heap

  • Your classes! Prefixes are helpful (e.g. ABCViewController)

    New type identifications Better at C++ classes dispatch and xpc types Heap-copied ^blocks (__NSMallocBlock__)

    Investigating the Heap

  • Your classes! Prefixes are helpful (e.g. ABCViewController)

    New type identifications Better at C++ classes dispatch and xpc types Heap-copied ^blocks (__NSMallocBlock__)

    Investigating the Heap

  • Your classes! Prefixes are helpful (e.g. ABCViewController)

    New type identifications Better at C++ classes dispatch and xpc types Heap-copied ^blocks (__NSMallocBlock__)

    Investigating the Heap

  • Your classes! Prefixes are helpful (e.g. ABCViewController)

    New type identifications Better at C++ classes dispatch and xpc types Heap-copied ^blocks (__NSMallocBlock__)

    Investigating the Heap

  • Your classes! Prefixes are helpful (e.g. ABCViewController)

    New type identifications Better at C++ classes dispatch and xpc types Heap-copied ^blocks (__NSMallocBlock__)

    Investigating the Heap

  • Leaked memory Inaccessibleno more pointers to it Cant ever be used again

    More memory over timeTypes of Heap Memory Growth

  • Leaked memory Inaccessibleno more pointers to it Cant ever be used again

    Abandoned memory Still referenced, but wasted Wont ever be used again

    More memory over timeTypes of Heap Memory Growth

  • Leaked memory Inaccessibleno more pointers to it Cant ever be used again

    Abandoned memory Still referenced, but wasted Wont ever be used again

    Cached memory Referenced and waiting Might never be used again

    More memory over timeTypes of Heap Memory Growth

  • Generational AnalysisDetecting abandoned memory and excessive caching

  • Generational Analysis

    Technique for measuring memory growth1. Reach a steady state2. Record first generation of active allocations3. Perform a series of operations, returning to steady state4. Record a new generation of incremental allocations5. Repeat steps 3 and 4

    Detecting abandoned memory and excessive caching

  • Generational Analysis

    Technique for measuring memory growth1. Reach a steady state2. Record first generation of active allocations3. Perform a series of operations, returning to steady state4. Record a new generation of incremental allocations5. Repeat steps 3 and 4

    Incremental allocations represent potential problems One-time growth, typical Repeatable memory growth, a real problem

    Detecting abandoned memory and excessive caching

  • Repetition reveals wasteAvoiding Memory Growth

    Time

    SteadyState

  • Repetition reveals wasteAvoiding Memory Growth

    Time

    SteadyState

    IntermediateState

  • Repetition reveals wasteAvoiding Memory Growth

    Time

    OriginalStateSteady

    State

    IntermediateState

  • Repetition reveals wasteAvoiding Memory Growth

    Time

    Warmup

    OriginalStateSteady

    State

    IntermediateState

  • Repetition reveals wasteAvoiding Memory Growth

    Time

    Warmup

    OriginalState

    Repeated

    SteadyState

    IntermediateState

  • Repetition reveals wasteAvoiding Memory Growth

    Time

    WarmupWasted

    OriginalState

    Repeated

    SteadyState

    IntermediateState

  • Heap fragmentationWhen Free Memory Isnt

    Fragmentation is poor utilization of malloc VM regions Effectively wasted space Impossible for system to reclaim

    NSSet

    CGFont

    CFURL UIView NSArray

  • How it happensHeap Fragmentation

  • How it happensHeap Fragmentation

    1.New malloc VM region is needed

  • How it happensHeap Fragmentation

    1.New malloc VM region is needed2. Region is filled until it cant fit more blocks

    NSObject

    UIButton

    NSArrayNSSetCAAnimation

  • How it happensHeap Fragmentation

    1.New malloc VM region is needed2. Region is filled until it cant fit more blocks3. Repeat steps 1 and 2 several times

    NSObject

    UIButton

    NSArrayNSSetCAAnimation

    UIWindow

    UIViewCGFont NSString

    MKMapView

    NSDateCFURL

    CGColor

    NSNumber

    NSData

    NSSet UIView

    NSArchiver

    CGPathNSInteger

    NSArrayNSDataNSString

    CGFont

    NSImage

  • How it happensHeap Fragmentation

    1.New malloc VM region is needed2. Region is filled until it cant fit more blocks3. Repeat steps 1 and 2 several times4.Most blocks are then freed, but not all

    NSSet

    CGFont

    CFURL UIView NSArray

  • Heap FragmentationAvoidance is the best policy

  • Heap Fragmentation

    Use Allocations instrument to identify Clear indicator is All Heap Allocations graph

    Avoidance is the best policy

  • Heap Fragmentation

    Use Allocations instrument to identify Clear indicator is All Heap Allocations graph

    Avoidance is the best policy

  • Heap Fragmentation

    Use Allocations instrument to identify Clear indicator is All Heap Allocations graph

    Avoidance is the best policy

  • Heap Fragmentation

    Use Allocations instrument to identify Clear indicator is All Heap Allocations graph

    Objective-C @autoreleasepool can help

    Avoidance is the best policy

  • Common problems and patternsObjective-C, Retain/Release

    Daniel DelwoodSoftware Radiologist

  • Retain/ReleaseObjective-Cs Ownership Model

    Reference counting ownership model based on -retain, -release When the count drops to zero, object is freed -autorelease just a delayed release Retain/release/autorelease rules established and easy to learn

  • Retain/ReleaseObjective-Cs Ownership Model

    Reference counting ownership model based on -retain, -release When the count drops to zero, object is freed -autorelease just a delayed release Retain/release/autorelease rules established and easy to learn

    Advanced Memory Management Programming Guide

  • Retain/ReleaseObjective-Cs Ownership Model

    Reference counting ownership model based on -retain, -release When the count drops to zero, object is freed -autorelease just a delayed release Retain/release/autorelease rules established and easy to learn

    Advanced Memory Management Programming Guide

    Deterministic, simple, and fast

  • Manual -retain/-release is tedious, error-prone Too many retains leaks Too many releases crashes

    Understanding ARCObjective-Cs Ownership Model

  • Manual -retain/-release is tedious, error-prone Too many retains leaks Too many releases crashes Retain cycles more leaks

    Understanding ARCObjective-Cs Ownership Model

  • Understanding ARCObjective-Cs Ownership Model

    Manual -retain/-release is tedious, error-prone Too many retains leaks Too many releases crashes Retain cycles more leaks

    Automatic Reference Counting (ARC) Compiler-assisted -retain/-release convention enforcement

  • Understanding ARCObjective-Cs Ownership Model

    Manual -retain/-release is tedious, error-prone Too many retains leaks Too many releases crashes Retain cycles more leaks

    Automatic Reference Counting (ARC) Compiler-assisted -retain/-release convention enforcement Doesnt solve retain cycles on its own

  • Understanding ARCObjective-Cs Ownership Model

    Manual -retain/-release is tedious, error-prone Too many retains leaks Too many releases crashes Retain cycles more leaks

    Automatic Reference Counting (ARC) Compiler-assisted -retain/-release convention enforcement Doesnt solve retain cycles on its own Provides additional tools like zeroing-weak references

  • Common problems under ARCObjective-Cs Ownership Model

    Memory growth Unreferenced retain cycles Leaks template Abandoned objects Generational analysis

    Messaging deallocated objects Undefined/non-deterministic behavior Best case: reproducible crashes usually in:

    objc_* (e.g. objc_msgSend, objc_storeStrong) -[NSObject doesNotRespondToSelector:]

    Worst case: works 99% of the time

  • Common problems under ARCObjective-Cs Ownership Model

    Memory growth Unreferenced retain cycles Leaks template Abandoned objects Generational analysis

    Messaging deallocated objects Undefined/non-deterministic behavior Best case: reproducible crashes usually in:

    objc_* (e.g. objc_msgSend, objc_storeStrong) -[NSObject doesNotRespondToSelector:]

    Worst case: works 99% of the time

  • Common problems under ARCObjective-Cs Ownership Model

    Memory growth Unreferenced retain cycles Leaks template Abandoned objects Generational analysis

    Messaging deallocated objects Undefined/non-deterministic behavior Best case: reproducible crashes usually in:

    objc_* (e.g. objc_msgSend, objc_storeStrong) -[NSObject doesNotRespondToSelector:]

    Worst case: works 99% of the time

  • Zombies template Debugging environment: NSZombieEnabled=1

    Seeking predictability and fixesMessaging Deallocated Objects

  • Zombies template Debugging environment: NSZombieEnabled=1 Instead of being deallocated, objects changed into Zombies

    Seeking predictability and fixesMessaging Deallocated Objects

  • Zombies template Debugging environment: NSZombieEnabled=1 Instead of being deallocated, objects changed into Zombies Zombies objects always crash when messaged

    Seeking predictability and fixesMessaging Deallocated Objects

    -[NSObject description]

  • Zombies template Debugging environment: NSZombieEnabled=1 Instead of being deallocated, objects changed into Zombies Zombies objects always crash when messaged

    Implications More deterministic memory isnt unchanged or reused Every zombie object leaks

    Dont use Zombies and Leaks together

    Seeking predictability and fixesMessaging Deallocated Objects

  • Zombies template Debugging environment: NSZombieEnabled=1 Instead of being deallocated, objects changed into Zombies Zombies objects always crash when messaged

    Implications More deterministic memory isnt unchanged or reused Every zombie object leaks

    Dont use Zombies and Leaks together

    Now available for iOS 7 devices

    Seeking predictability and fixesMessaging Deallocated Objects

  • DemoRetain/Release, leaks and crashes

  • Steps to fix leaks/crashesApplying It to Your App

    Switch to ARC Run the Static Analyzer

  • Steps to fix leaks/crashesApplying It to Your App

    Switch to ARC Run the Static Analyzer Zombies template is a great first resort for crashes

  • Steps to fix leaks/crashesApplying It to Your App

    Switch to ARC Run the Static Analyzer Zombies template is a great first resort for crashes Backtrace for +alloc does not tell the whole story

  • Steps to fix leaks/crashesApplying It to Your App

    Switch to ARC Run the Static Analyzer Zombies template is a great first resort for crashes Backtrace for +alloc does not tell the whole story Save time by pairing Retain/Releases

  • Needle in a smaller haystackRetain/Release Pairing

    Manual pairing assistantHeuristic-based automatic pairing (better in ARC and -o0)

  • Profiling Debug configurationRetain/Release Pairing

    Profile action defaults to Release configuration Release great for Time Profiling Debug useful for memory tools

  • Profiling Debug configurationRetain/Release Pairing

    Profile action defaults to Release configuration Release great for Time Profiling Debug useful for memory tools

  • With great keywords comes great responsibilityCommon Objective-C Issues

    ^block captures and retain cycles __weak variables __unsafe_unretained@autoreleasepool and __autoreleasing Working with C-APIs and __bridge casts

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference self

    Common Objective-C Issues^block captures and retain cycles

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference self

    _obsToken = [center addObserverForName:@MyNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.document = [note object];}];

    Common Objective-C Issues^block captures and retain cycles

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference self

    _obsToken = [center addObserverForName:@MyNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.document = [note object];}];

    Common Objective-C Issues^block captures and retain cycles

    _obsToken retained by self

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference self

    _obsToken = [center addObserverForName:@MyNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.document = [note object];}];

    Common Objective-C Issues^block captures and retain cycles

    _obsToken retained by self ^block retained by _obsToken

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference self

    _obsToken = [center addObserverForName:@MyNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.document = [note object];}];

    Common Objective-C Issues^block captures and retain cycles

    _obsToken retained by self ^block retained by _obsToken

    self retained by ^block

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference self

    _obsToken = [center addObserverForName:@MyNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { self.document = [note object];}];

    Common Objective-C Issues^block captures and retain cycles

    _obsToken retained by self ^block retained by _obsToken

    self retained by ^block Retain Cycle

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference selfUse __weak keyword to break cycles

    When non-ARC, use __block to indicate dont retain

    Common Objective-C Issues^block captures and retain cycles

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference selfUse __weak keyword to break cycles

    When non-ARC, use __block to indicate dont retain

    Common Objective-C Issues^block captures and retain cycles

    __weak __typeof(self) weaklyNotifiedSelf = self;_obsToken = [center addObserverForName:@MyNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { weaklyNotifiedSelf.document = [note object];}];

  • ^blocks capture referenced objects strongly by default Instance variables implicitly reference selfUse __weak keyword to break cycles

    When non-ARC, use __block to indicate dont retain

    Common Objective-C Issues^block captures and retain cycles

    __weak __typeof(self) weaklyNotifiedSelf = self;_obsToken = [center addObserverForName:@MyNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { weaklyNotifiedSelf.document = [note object];}];

  • ^block captures and retain cyclesCommon Objective-C Issues

    ^blocks capture referenced objects strongly by default Instance variables implicitly reference selfUse __weak keyword to break cycles

    When non-ARC, use __block to indicate dont retain

    Look out for persisting relationships Registrations (e.g. NSNotifications, error callbacks) Recurrences (e.g. timers, handlers) One-time executions (dispatch_async, dispatch_after) are fine

  • Weak on demand__weak variables

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    __weak variables

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive uses

    __weak variables

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive usesNever do -> dereference

    __weak variables

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive usesNever do -> dereference

    __weak variables

    if (weakObject) { [weakObject->delegate customerNameChanged:name]}

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive usesNever do -> dereference

    __weak variables

    if (weakObject) { [weakObject->delegate customerNameChanged:name]}

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive usesNever do -> dereference

    __weak variables

    if (weakObject) { [weakObject->delegate customerNameChanged:name]}

    [weakObject.delegate customerNameChanged:name]

    id strongObject = weakObject;if (strongObject) { [strongObject->delegate customerNameChanged:name]}

    or

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive usesNever do -> dereference

    __weak variables

    if (weakObject) { [weakObject->delegate customerNameChanged:name]}

    [weakObject.delegate customerNameChanged:name]

    id strongObject = weakObject;if (strongObject) { [strongObject->delegate customerNameChanged:name]}

    or

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive usesNever do -> dereference

    __weak variables

    if (weakObject) { [weakObject->delegate customerNameChanged:name]}

    [weakObject.delegate customerNameChanged:name]

    id strongObject = weakObject;if (strongObject) { [strongObject->delegate customerNameChanged:name]}

    or

  • Weak on demand

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive usesNever do -> dereference

    __weak variables

    if (weakObject) { [weakObject->delegate customerNameChanged:name]}

    [weakObject.delegate customerNameChanged:name]

    id strongObject = weakObject;if (strongObject) { [strongObject->delegate customerNameChanged:name]}

    or

  • Weak on demand__weak variables

    Every use of __weak validates reference nil is always a possible result

    Avoid consecutive usesNever do -> dereferenceDo not over-use __weak

    __weak variables are not free

  • Risk vs. Reward__unsafe_unretained

  • Risk vs. Reward__unsafe_unretained

    No ARC-managed -retain/-release

  • Risk vs. Reward__unsafe_unretained

    No ARC-managed -retain/-release@property (assign) id => __unsafe_unretained id

  • Risk vs. Reward__unsafe_unretained

    No ARC-managed -retain/-release@property (assign) id => __unsafe_unretained id Easily can lead to crashes dangling references

  • Risk vs. Reward__unsafe_unretained

    No ARC-managed -retain/-release@property (assign) id => __unsafe_unretained id Easily can lead to crashes dangling referencesUnretained framework references

  • Risk vs. Reward__unsafe_unretained

    No ARC-managed -retain/-release@property (assign) id => __unsafe_unretained id Easily can lead to crashes dangling referencesUnretained framework references Last resort keyword

  • Object sent -retain/-autorelease upon assignment

    ARC and out-parameters__autoreleasing

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **)

    ARC and out-parameters__autoreleasing

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen

    ARC and out-parameters__autoreleasing

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:outError]; if (parsed) { // < use dictionary > return YES; } else { return NO; } }}

    ARC and out-parameters__autoreleasing

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:outError]; if (parsed) { // < use dictionary > return YES; } else { return NO; } }}

    ARC and out-parameters__autoreleasing

    Assignment to __autoreleasing outError

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:outError]; if (parsed) { // < use dictionary > return YES; } else { return NO; } }}

    ARC and out-parameters__autoreleasing

    Leaving @autoreleasepool {} scope triggers delayed -release

    Assignment to __autoreleasing outError

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:outError]; if (parsed) { // < use dictionary > return YES; } else { return NO; } }}

    ARC and out-parameters__autoreleasing

    Leaving @autoreleasepool {} scope triggers delayed -release

    Returns deallocated NSError object to caller

    Assignment to __autoreleasing outError

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { NSError *localError = nil; BOOL wasSuccessful = YES; @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:&localError]; if (parsed) { // < use dictionary > } else { wasSuccessful = NO; } } if (!wasSuccessful && outError) *outError = localError; return wasSuccessful;}

    ARC and out-parameters__autoreleasing

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { NSError *localError = nil; BOOL wasSuccessful = YES; @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:&localError]; if (parsed) { // < use dictionary > } else { wasSuccessful = NO; } } if (!wasSuccessful && outError) *outError = localError; return wasSuccessful;}

    ARC and out-parameters__autoreleasing

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { NSError *localError = nil; BOOL wasSuccessful = YES; @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:&localError]; if (parsed) { // < use dictionary > } else { wasSuccessful = NO; } } if (!wasSuccessful && outError) *outError = localError; return wasSuccessful;}

    ARC and out-parameters__autoreleasing

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { NSError *localError = nil; BOOL wasSuccessful = YES; @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:&localError]; if (parsed) { // < use dictionary > } else { wasSuccessful = NO; } } if (!wasSuccessful && outError) *outError = localError; return wasSuccessful;}

    ARC and out-parameters__autoreleasing

  • Object sent -retain/-autorelease upon assignmentOut-parameters are __autoreleasing by default (e.g. NSError **) If @autoreleasepool wraps assignment, crashes happen- (BOOL)startWithConfigurationURL:(NSURL*)url error:(NSError**)outError { NSError *localError = nil; BOOL wasSuccessful = YES; @autoreleasepool { // < get response from url > NSDictionary *parsed = [NSJSONSerialization JSONObjectWithData:response options:0 error:&localError]; if (parsed) { // < use dictionary > } else { wasSuccessful = NO; } } if (!wasSuccessful && outError) *outError = localError; return wasSuccessful;}

    ARC and out-parameters__autoreleasing

    __autoreleasing assignment outside @autoreleasepool {}

  • Working with C-based APIs__bridge casts

    ARC manages at Objective-C level

  • Working with C-based APIs__bridge casts

    ARC manages at Objective-C level C-based APIs: CoreFoundation, CoreGraphics, void* context,

  • Working with C-based APIs__bridge casts

    ARC manages at Objective-C level C-based APIs: CoreFoundation, CoreGraphics, void* context, Three conversion primitives:

    __bridge T : just type casting __bridge_transfer T / CFBridgingRelease() : also issues a -release __bridge_retained T / CFBridgingRetain() : also issues a -retain

  • Working with C-based APIs__bridge casts

    ARC manages at Objective-C level C-based APIs: CoreFoundation, CoreGraphics, void* context, Three conversion primitives:

    __bridge T : just type casting __bridge_transfer T / CFBridgingRelease() : also issues a -release __bridge_retained T / CFBridgingRetain() : also issues a -retain

    Incorrect bridging leads to leaks/crashes

  • Using them correctly

    1. CF +1 ARC-managed id : __bridge_transfer T2. CF +0ARC-managedid : __bridge T3.ARC-managedidCF +0 : __bridge T4.ARC-managedidCF +1: __bridge_retained T

    __bridge casts

  • Using them correctly

    1. CF +1 ARC-managed id : __bridge_transfer T2. CF +0ARC-managedid : __bridge T3.ARC-managedidCF +0 : __bridge TEffectively creates an __unsafe_unretained CF reference!

    4.ARC-managedidCF +1: __bridge_retained T

    __bridge casts

  • Using them correctly

    4.ARC-managedidCF +1: __bridge_retained T

    __bridge casts

    1. CF +1 ARC-managed id : __bridge_transfer T2. CF +0ARC-managedid : __bridge T3.ARC-managedidCF +0 : __bridge TEffectively creates an __unsafe_unretained CF reference!CFStringRef stringRef = NULL;...NSString *logInfo = [[NSString alloc] initWithFormat:...];stringRef = (__bridge CFStringRef)logInfo;... CFURLRef url = CFURLCreateWithString(NULL, stringRef, baseURL);

  • Using them correctly

    4.ARC-managedidCF +1: __bridge_retained T

    __bridge casts

    1. CF +1 ARC-managed id : __bridge_transfer T2. CF +0ARC-managedid : __bridge T3.ARC-managedidCF +0 : __bridge TEffectively creates an __unsafe_unretained CF reference!CFStringRef stringRef = NULL;...NSString *logInfo = [[NSString alloc] initWithFormat:...];stringRef = (__bridge CFStringRef)logInfo;... CFURLRef url = CFURLCreateWithString(NULL, stringRef, baseURL);

  • Using them correctly

    4.ARC-managedidCF +1: __bridge_retained T

    __bridge casts

    1. CF +1 ARC-managed id : __bridge_transfer T2. CF +0ARC-managedid : __bridge T3.ARC-managedidCF +0 : __bridge TEffectively creates an __unsafe_unretained CF reference!CFStringRef stringRef = NULL;...NSString *logInfo = [[NSString alloc] initWithFormat:...];stringRef = (__bridge CFStringRef)logInfo;... CFURLRef url = CFURLCreateWithString(NULL, stringRef, baseURL);

    logInfo leaves scope, released

  • Using them correctly

    4.ARC-managedidCF +1: __bridge_retained T

    __bridge casts

    1. CF +1 ARC-managed id : __bridge_transfer T2. CF +0ARC-managedid : __bridge T3.ARC-managedidCF +0 : __bridge TEffectively creates an __unsafe_unretained CF reference!CFStringRef stringRef = NULL;...NSString *logInfo = [[NSString alloc] initWithFormat:...];stringRef = (__bridge CFStringRef)logInfo;... CFURLRef url = CFURLCreateWithString(NULL, stringRef, baseURL);

    logInfo leaves scope, released

    stringRef not valid

  • Using them correctly__bridge casts

    1. CF +1 ARC-managed id : __bridge_transfer T2. CF +0ARC-managedid : __bridge T3.ARC-managedidCF +0 : __bridge TEffectively creates an __unsafe_unretained CF reference!

    4.ARC-managedidCF +1: __bridge_retained TCFStringRef stringRef = NULL;...NSString *logInfo = [[NSString alloc] initWithFormat:...];stringRef = (__bridge_retained CFStringRef)logInfo;... CFURLRef url = CFURLCreateWithString(NULL, stringRef, baseURL);CFRelease(stringRef)

  • Testing and tipsBeing a Good Citizen

  • Real-world user scenariosMemory Testing

  • Real-world user scenariosMemory Testing

    Test on constrained devices

  • Real-world user scenariosMemory Testing

    Test on constrained devices First install/first launch

  • Real-world user scenariosMemory Testing

    Test on constrained devices First install/first launch Large dataset

  • Real-world user scenariosMemory Testing

    Test on constrained devices First install/first launch Large dataset Background launch

  • Real-world user scenariosMemory Testing

    Test on constrained devices First install/first launch Large dataset Background launch

  • Real-world user scenariosMemory Testing

    Test on constrained devices First install/first launch Large dataset Background launch

    Especially for leaked/abandoned memory

  • Where there are not enough free pagesSystem Memory Pressure

    Pages must be evicted Clean and purgeable pages can be thrown awayDirty pages

  • Where there are not enough free pagesSystem Memory Pressure

    Pages must be evicted Clean and purgeable pages can be thrown awayDirty pages

    On OSX, compressed or saved to disk (expensive)

    Building Efficient OS X Apps Nob HillTuesday 4:30PM

  • Where there are not enough free pagesSystem Memory Pressure

    Pages must be evicted Clean and purgeable pages can be thrown awayDirty pages

    On OSX, compressed or saved to disk (expensive)

    On iOS, memory warnings issued and processes terminated

    Building Efficient OS X Apps Nob HillTuesday 4:30PM

  • and avoiding terminationiOS: Memory Warnings

  • and avoiding terminationiOS: Memory Warnings

    Do not be the biggest Dirty memory is what counts VM Tracker

  • and avoiding terminationiOS: Memory Warnings

    Do not be the biggest Dirty memory is what counts VM Tracker

    Make sure your application gets a chance to respond Avoid large, rapid allocations Notifications arrive on main thread

  • and avoiding terminationiOS: Memory Warnings

    Do not be the biggest Dirty memory is what counts VM Tracker

    Make sure your application gets a chance to respond Avoid large, rapid allocations Notifications arrive on main threadUIApplicationDidReceiveMemoryWarningNotification-[id -applicationDidReceiveMemoryWarning:]-[UIViewController didReceiveMemoryWarning]

  • and avoiding terminationiOS: Memory Warnings

    Do not be the biggest Dirty memory is what counts VM Tracker

    Make sure your application gets a chance to respond Avoid large, rapid allocations Notifications arrive on main thread

    Consider freeing up memory before entering background

    UIApplicationDidReceiveMemoryWarningNotification-[id -applicationDidReceiveMemoryWarning:]-[UIViewController didReceiveMemoryWarning]

  • and avoiding terminationiOS: Memory Warnings

    Do not be the biggest Dirty memory is what counts VM Tracker

    Make sure your application gets a chance to respond Avoid large, rapid allocations Notifications arrive on main thread

    Consider freeing up memory before entering background

    UIApplicationDidReceiveMemoryWarningNotification-[id -applicationDidReceiveMemoryWarning:]-[UIViewController didReceiveMemoryWarning]

    -[id -applicationDidEnterBackground:]

  • Summary

    Be proactive: monitor, test, investigateAvoid memory spikesDont allow unbounded heap/VM growthUse language tools effectively: __weak, @autoreleasepool, etc.

  • More Information

    Dave DeLongDeveloper Tools [email protected]

    Instruments DocumentationInstruments User GuideInstruments User Referencehttp://developer.apple.com/ Developer Library

    Apple Developer Forumshttp://devforums.apple.com

  • Related Sessions

    Building Efficient OS X Apps Nob HillTuesday 4:30PM

    Advances in Objective-C MissionTuesday 4:30PM

    Energy Best Practices MarinaThursday 10:15AM

    Core Data Performance Optimization and Debugging Nob HillWednesday 2:00PM

    Designing Code for Performance Nob HillFriday 9:00AM

  • Labs

    Instruments and Performance Lab Tools Lab BThursday 3:15PM

    Objective-C and LLVM Lab Tools Lab CThursday 2:00PM

    LLDB and Instruments Lab Tools Lab CFriday 10:15AM