跪拜 Guibai
← All articles
iOS · Xcode

Pinpointing iOS Scroll Stutter with Xcode's Animation Hitches

By _瑞 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Hitches give a frame-level audit trail that ends the "it feels slow" argument with hard timing data, and the hitch-type taxonomy tells you immediately whether to profile your own code, audit your layer tree, or suspect thermal throttling.

Summary

A late frame is a hitch, and Instruments records exactly how late it was, which phase blew the budget, and what the CPU was doing during that window. The tool breaks each frame's lifecycle into User Events, Commits, Renders, and GPU segments, then overlays Thread State Trace and Thermal State to distinguish app-level bottlenecks from system pressure.

A real list-scrolling investigation walks through the workflow: run under Profile, capture a scroll session in Animation Hitches, inspect Frame Lifetimes to isolate the pre-commit region where the budget ran out, and switch to Time Profiler on that interval. The culprit was a main-thread `UIGraphicsImageRenderer` call that forced synchronous JPEG decode and bitmap draw.

The piece also catalogs every hitch type — Pre-Commit latency, Expensive Commit, Commit-to-Render gap, Expensive Rendering, CPU-to-GPU latency, Expensive GPU, and Delayed Frame Swap — with the typical causes for each, so a developer knows which track to inspect next.

Takeaways
A frame becomes a hitch when its actual presentation time is later than its expected vsync-aligned deadline.
Hitch Duration is the gap between expected and actual on-screen time; Acceptable Latency is the total budget from frame start to deadline.
Severity is measured in missed refresh intervals: Low (<1), Moderate (1–2), High (>2).
Pre-Commit latency means the budget was exhausted before Core Animation Commit even began, pointing to main-thread business logic, image decode, or lock contention.
Expensive Commit means layout, Auto Layout, drawRect, or layer-tree packaging consumed the budget during the commit phase.
Commit-to-Render latency and CPU-to-GPU latency are inter-stage waiting periods, not directly attributable to a single app function.
Expensive Rendering means the Render Server's CPU-side layer-tree walk and command generation took too long; check layer count, masks, shadows, and blur.
Expensive GPU means the GPU execution itself exceeded the budget; inspect off-screen passes, overdraw, large textures, and blending.
Frame Lifetimes overlap across consecutive frames because the pipeline processes multiple frames concurrently.
Time Profiler on a selected pre-commit interval directly reveals the heaviest user-code stack, with a person icon marking user code.
Thread State Trace shows whether a thread was Running, Runnable, Blocked, or Preempted — essential when CPU usage is low but the UI is stuck.
Thermal State records the system's heat-pressure level (Nominal, Fair, Serious, Critical) and can amplify hitches without being the root cause.
Hangs track whether the main thread's RunLoop is stuck processing one task and cannot return to accept new events.
Conclusions

Animation Hitches turns a subjective performance argument into a precise, timestamped breakdown of which pipeline stage missed its deadline and by how many milliseconds.

The hitch-type classification is cumulative, not isolated: 'Expensive Commit' doesn't mean the commit phase alone was slow, only that the budget was exhausted by the time commit finished.

Overlapping Frame Lifetimes are not a bug; they are the expected signature of a pipelined rendering architecture where App, Render Server, and GPU work on different frames simultaneously.

Thread State Trace fills the diagnostic gap that Time Profiler cannot cover: a blocked main thread consumes no CPU and leaves no hot stack, but the trace records exactly how long it sat waiting.

Thermal State is a confounding variable, not a root cause; a profile captured under Serious thermal pressure should be discarded and re-collected after the device cools.

Apple's Instruments treats SpringBoard commits as separate entries in the Commits track, reminding developers that system UI layers also participate in frame budgeting.

Concepts & terms
Hitch
A frame whose actual on-screen presentation time is later than its expected vsync-aligned deadline. Instruments records the hitch duration, severity, and the pipeline stage where the time budget was exhausted.
Hitch Type
A classification that identifies which rendering-pipeline phase consumed the frame's time budget: Pre-Commit latency, Expensive Commit, Commit-to-Render latency, Expensive Rendering, CPU-to-GPU latency, Expensive GPU, or Delayed Frame Swap.
Frame Lifetimes
The total time interval from the start of a frame's processing to its actual on-screen presentation, visualized as a bar spanning User Events, Commits, Renders, and GPU phases.
Core Animation Commit
The process where the app packages the current frame's layer-tree changes and submits them to the Render Server. Instruments' Commits track records the timing of this submission for each participating process.
Render Server
A system process separate from the app that walks the submitted layer tree on the CPU, resolves compositing, animations, and off-screen passes, and generates GPU-executable rendering commands.
Thread State Trace
An Instruments track that records whether a thread was Running, Runnable, Blocked, Preempted, or Idle over time, used to diagnose unresponsiveness when CPU usage is low.
Thermal State
A system-reported heat-pressure level (Nominal, Fair, Serious, Critical) that triggers performance throttling; it can amplify hitches but is not a root cause of app-level slowness.
Hang
A condition where the main thread's RunLoop is stuck processing a single task and cannot return to accept new events, making the app appear frozen to the user.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗