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
Top Related