Mobile Development 26 min read

Comprehensive Guide to iOS App Startup Optimization and Multi‑Dimensional Performance Analysis

The guide details how Gaode Map’s iOS app cut cold‑start time by over 65% to sub‑400 ms through systematic analysis of launch phases, Mach‑O loading, multi‑dimensional runtime metrics, automated static source parsing, and visual trace tooling, demonstrating a repeatable method for sustained launch‑time optimization.

Amap Tech
Amap Tech
Amap Tech
Comprehensive Guide to iOS App Startup Optimization and Multi‑Dimensional Performance Analysis

Recently the Gaode Map iOS app completed a startup‑optimization project that reduced the launch time of both iOS and Android by more than 65%, achieving sub‑400 ms on an iPhone 7. This article summarizes the technical methods, tools, and code used to achieve that improvement.

Startup Types and Phases

Three startup types are distinguished:

Cold : the app is launched after a full restart, no process or memory exists.

Warm : the app was terminated recently; some memory remains but no process.

Resume : the app is only paused; both memory and process stay alive.

Analysis usually focuses on the Cold startup because it provides a stable baseline. Test devices such as iPhone 7 (iOS) and stable Android models (Vivo, etc.) are used, and temperature, network conditions, and iCloud login state are controlled.

iOS Launch Process

The launch consists of loading the Mach‑O binary and runtime initialization. The loader checks the file’s magic number (e.g., 0xfeedface → MH_MAGIC , 0xfeedfacf → MH_MAGIC_64 , etc.) and then forks a process, calls execve , loads dyld , and performs rebase, binding, lazy binding, and symbol export. The dyld_stub_binder resolves stub jumps to real addresses.

Mach‑O file types include MH_OBJECT , MH_EXECUTE , MH_DYLIB , MH_DYLINKER , MH_DYLIB_STUB , MH_DSYM , etc.

Attribute Constructor Example

#include <stdio.h>
__attribute__((constructor))
static void prepare() {
    printf("%s\n", "prepare");
}

__attribute__((destructor))
static void end() {
    printf("%s\n", "end");
}

void showHeader() {
    printf("%s\n", "header");
}

Running the binary prints:

ming@mingdeMacBook-Pro macho_demo % ./main "hi"
prepare
hi
end

Runtime Initialization Steps

Load class extensions

Load C++ static objects

Call +load methods

Execute main

Application initialization (up to applicationDidFinishLaunchingWithOptions )

Render the first frame (up to viewDidAppear )

Instrumentation Tools

Apple’s System Trace provides a full view of thread states, CPU usage, memory allocation, I/O, and even thermal data. Custom signposts can be added via sys/kdebug_signpost.h . XCTest performance APIs (available since Xcode 11) and the “App Launch” Instruments template are also useful, though they lack built‑in aggregation and diff capabilities.

Multi‑Dimensional Metrics

Main‑thread time (most visible to users)

CPU usage (per‑thread, per‑state, overall load)

Memory footprint (real usage via WebKit’s MemoryFootprintCocoa.cpp )

Network latency (DNS, SSL, first‑byte, response time; can be hooked with Fishhook)

I/O latency (instrumented with Frida)

References to WWDC sessions and open‑source projects (e.g., Messier , Tencent/GT ) are provided for deeper analysis.

JSON Trace Example

{"name":"[SMVeilweaa]upVeilState:","cat":"catname","ph":"B","pid":2381,"tid":0,"ts":21},
{"name":"[SMVeilweaa]tatLaunchState:","cat":"catname","ph":"B","pid":2381,"tid":0,"ts":4557},
{"name":"[SMVeilweaa]tatTimeStamp:state:","cat":"catname","ph":"B","pid":2381,"tid":0,"ts":4686},
{"name":"[SMVeilweaa]tatTimeStamp:state:","cat":"catname","ph":"E","pid":2381,"tid":0,"ts":4727},
…

These events can be visualized with Chrome’s Trace Viewer to produce flame graphs, where the ph field indicates method start (B) or end (E).

Static Project Parsing

The tool parses .xcworkspace to locate .xcodeproj files, then walks the PBXGroup hierarchy to collect all source files ( .m , .mm ). Example of .xcworkspace XML:

<?xml version="1.0" encoding="UTF-8"?>
<Workspace version="1.0">
    <FileRef location="group:GCDFetchFeed.xcodeproj"/>
    <FileRef location="group:Pods/Pods.xcodeproj"/>
</Workspace>

Key Xcodeproj sections (PBXBuildFile, PBXGroup, PBXSourcesBuildPhase, etc.) are modeled to retrieve absolute file paths, handling relative components like ../ .

Objective‑C Token Definition

// Token delimiters [](){}.&=*+-<>~!/%^|?:;,#@
public enum OCTK {
    case unknown
    case eof
    case eod
    case comment
    case identifier
    case numericConstant(OCTkNumericConstant)
    case charConstant
    case stringLiteral
    case wideStringLiteral
    case angleStringLiteral
    case punctuators(OCTkPunctuators)
    case keyword(OCTKKeyword)
    case atKeyword(OCTKAtKeyword)
}

Parsing states for method extraction are defined as:

private enum RState {
    case normal
    case eod
    case methodStart
    case methodReturnEnd
    case methodNameEnd
    case methodParamStart
    case methodContentStart
    case methodParamTypeStart
    case methodParamTypeEnd
    case methodParamEnd
    case methodParamNameEnd
    case at
    case atImplementation
    case normalBlock
}

AST nodes for OC code:

public struct OCNode {
    public var type: OCNodeType
    public var subNodes: [OCNode]
    public var identifier: String
    public var lineRange: (Int,Int)
    public var source: String
}
public enum OCNodeType { case `default`; case root; case `import`; case `class`; case method }

Parallel parsing is performed with dispatch_group to process thousands of source files efficiently (≈2.5 min for 10 k files on a dual‑core i7).

HTML Result Presentation

Method source code is stored in a dictionary and displayed on demand. Newlines and spaces are converted to <br/> and &nbsp; . Clicking a method name runs a small JavaScript function:

function sourceShowHidden(sourceIdName) {
    var sourceCode = document.getElementById(sourceIdName);
    sourceCode.style.display = "block";
}

The final UI combines dynamic trace data with static source lookup, enabling developers to see which methods dominate launch time, how their implementations changed across versions, and whether they perform I/O, spawn threads, or interact with queues.

Conclusion

The article demonstrates that systematic, multi‑dimensional analysis—combining runtime instrumentation, JSON trace processing, and static source parsing—can dramatically shrink iOS app launch time and keep the performance stable over the product lifecycle.

Instrumentationperformance optimizationiOStracingObjective-Capp startuptool development
Amap Tech
Written by

Amap Tech

Official Amap technology account showcasing all of Amap's technical innovations.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.