Mobile Development 10 min read

Optimizing iOS App Startup by Adjusting GCD Queue QoS and Reducing Main Thread Preemption

By analyzing thread preemption on low‑end iPhones, this article demonstrates how selecting appropriate GCD queue QoS levels—favoring Utility or Background over User‑Initiated—reduces main‑thread contention, improves launch screen rendering by ~100 ms, and accelerates message list first‑load by up to 1.5 s without altering business logic.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Optimizing iOS App Startup by Adjusting GCD Queue QoS and Reducing Main Thread Preemption

When optimizing app launch, developers often increase concurrency, but on iOS the Grand Central Dispatch (GCD) framework governs thread scheduling. This article investigates whether adding concurrency truly helps startup and which GCD queue priority should be used.

Using Instruments on a low‑end iPhone 7p (A10, 2 active cores) and a high‑end iPhone 12 (A14, 6 active cores), the authors observed that the main thread spends a large proportion of time in Preempted and Runnable states on the low‑end device (up to 21 %). This indicates heavy CPU contention and that the main thread can be pre‑empted by other threads.

Experimentation

Four demo groups were created to measure the impact of different GCD QoS classes on main‑thread preemption:

Group 1: DispatchQoS.userInteractive – resulted in 74 % preempted+runnable time.

Group 2: default (no QoS, which defaults to User‑Initiated ) – 73 % preempted+runnable time.

Group 3: DispatchQoS.utility – reduced preempted+runnable time to 1.3 %.

Group 4: DispatchQoS.background – also around 1.3 % preempted+runnable time.

Code example for Group 1:

for _ in 1...100 {
    let queue = DispatchQueue(label: "serialQueue", qos: .userInteractive)
    queue.async {
        while true {}
    }
}
while true {}

Code example for Group 3:

for _ in 1...100 {
    let queue = DispatchQueue(label: "serialQueue", qos: .utility)
    queue.async {
        while true {}
    }
}
while true {}

The results show that higher‑priority QoS classes (User‑Interactive, User‑Initiated) can aggressively pre‑empt the main thread, while Utility and Background have minimal impact.

QoS vs. Thread Priority

Apple maps QoS classes to Mach thread priorities. The relationship (derived from documentation and source code) is:

QoS

Priority

User‑Interactive

46 (47 for UI thread)

User‑Initiated

37

Utility

20

Background

4

Even though the main thread starts with priority 47, the scheduler dynamically lowers it, but never below ~29, keeping it above Utility (20). This explains why Utility‑QoS queues rarely pre‑empt the main thread.

Practical Optimization

In the Feishu app, many asynchronous queues were created with the default QoS (User‑Initiated), causing noticeable main‑thread preemption on low‑end devices. By moving non‑essential queues to Utility or Background, the main thread gained CPU time, resulting in a 100 ms reduction in first‑screen display and a 1500 ms reduction in message‑list first‑load.

To avoid degrading other critical paths, the team identified which asynchronous tasks are required for the first‑screen and first‑load (e.g., database reads, network requests) and kept those on higher QoS, while demoting unrelated work.

Conclusion

Increasing concurrency alone is insufficient for launch optimization on low‑end iOS devices; CPU becomes the bottleneck and thread pre‑emption must be managed. Selecting appropriate GCD QoS—Utility or Background for non‑critical work—significantly improves launch performance without changing business logic.

performanceiOSConcurrencystartup optimizationQoSgcd
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

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.