Saurabh 😎

WWDC 2010: Advanced Performance Optimization on iPhone OS, Part 2

Focus of talk is working with data effectively (both in-memory and serialized)

Memory

iPhone has virtual memory, but no swap file

Each page can be in one state:
Nonresident
Resident and clean
Resident and dirty

Nonresident page access causes page fault

Resident = page is in physical memory

Anonymous memory (e.g. malloc) is always dirty

File-backed memory starts clean, becomes dirty if modified

If a page is clean, then it must be file-backed and unmodified - hence, clean pages can be reused without having to write to disk (since original contents are in a file)

VM Tracker instrument takes snapshot of virtual memory usage at a point in time (so end up with series of samples over time)

Check growth in dirty size of regions:

See also: WWDC 2010 Advanced Memory Analysis with Instruments

Low memory notifications - unique to iOS!

Sent when too much total dirty memory in system
First threshold: apps receive notification
Second threshold: background apps exit, foreground app warned
Final threshold: foreground app killed

applicationDidReceiveMemoryWarning in app delegate

For multi-tasking, tradeoff between releasing resources in applicationDidEnterBackground: and also keeping enough resources to enable fast loading if user switches back to it

Choose right method for images:
[UIImage imageNamed:] for images used in UI elements (e.g. custom controls, cells)
[UIImage imageWithContentsOfFile:] for all other images

ImageIO - refer to Creating a Thumbnail Image in the Image I/O Programming Guide to create low-memory thumbnails from large images

Overall memory goal: reduce dirty memory usage

Foundation

Unique performance of NSMutableArray:
Insertion/deletion at beginning of array is amortized O(1) (usually is O(n) in textbooks), so can be used as queue
Becomes a tree at ~250,000 elements, so access to individual elements becomes O(log N)

-hash good enough implementation: XOR -hash of each instance variable object

Property Lists:

Don't use NSCoding with large object graphs

File System

Use System Usage instrument - look for unexpected I/O and backtrace that caused it

Avoid [NSData dataWithContentsOfFile:] for large files since it reads entire file into buffer
Alternative 1: demand page data with [NSData dataWithContentsOfMappedFile:]
Alternative 2: incrementally read/seek with [NSFileHandle readDataOfLength:]

Avoid repeatedly open()/stat()'ing a file since it incurs an extra iOS-specific check to see if your app has access to that path

Databases

Useful for incremental reading and datasets larger than memory

Core Data features: automatic schema management, iPhone specific enhancements

SQLite tips:

Scaling Tips

Avoid bringing in entire data set for view loading time

Test and profile with different data set sizes

For loading sections quickly, Contacts app uses a separate table for pre-computed section counts, maintained by triggers

For loading table view cells quickly:
LIMIT/OFFSET is not particular efficient in SQLite, but works if iterating over small index
Can also use "scrolling cursor" method