fixing memory issues
DESCRIPTION
Fixing Memory issues in iOSTRANSCRIPT
-
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