How HLL’s Thread Governance Cut Crashes and Boost iOS Driver App Performance
This article explains how the HLL iOS driver team identified excessive global‑queue usage, thread‑switch overhead, deadlocks and UI‑thread violations, then introduced a priority‑aware queue pool, refined concurrency controls, and built long‑term monitoring to dramatically reduce crashes and improve performance.
Driver team iOS is responsible for the domestic freight driver‑side iOS app and supports the core business infrastructure.
Background
Rapid business growth led to many technical debts; the driver app suffers from overheating, high battery consumption and frequent crashes.
Drivers use low‑end phones and stay online for long periods (average 3.5 hours), making performance optimization challenging.
The thread‑governance project was launched to reduce crashes, overheating and power drain.
Problem Analysis
Abuse of the global queue with default priority
dispatch_async(dispatch_get_global_queue(0,0), ^{ /* TODO */ });Developers often use the global queue default priority, causing many tasks to compete on a single thread.
Unnecessary thread switches
dispatch_async(dispatch_get_global_queue(0,0), ^{ /* loadData */ });
dispatch_async(dispatch_get_main_queue(), ^{ /* refresh UI */ });Switching between background and main queues for trivial work adds overhead.
High‑concurrency without control
// async location fetch
- (void)getDriverCurrentAddress:(void(^)(HLLAddressComponent *component))complete { … }Multiple concurrent calls to this method can cause deadlocks when the global queue creates too many threads.
UI updates on background threads Updating UI from a background thread leads to occasional crashes (psynch cvwait, mutexwait, etc.).
Thread‑safety issues Crashes with pthread kill, objc_release, malloc errors indicate unsynchronized reads/writes.
Solution Overview
New queue management and allocation Replace the default global queue with a set of serial queues whose count matches CPU cores, each assigned a specific QoS (UserInteractive, UserInitiated, Utility, Background, Default).
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface HLLQueuePool : NSObject
extern dispatch_queue_t HLLQueueForQoSUserInteractive(void);
extern dispatch_queue_t HLLQueueForQoSUserInitiated(void);
extern dispatch_queue_t HLLQueueForQoSUtility(void);
extern dispatch_queue_t HLLQueueForQoSBackground(void);
extern dispatch_queue_t HLLQueueForQoSDefault(void);
@end
NS_ASSUME_NONNULL_ENDBusiness code now dispatches to the appropriate QoS queue, e.g.:
dispatch_async(HLLQueueForQoSUserInitiated(), ^{ /* heavy task */ });Refactor high‑concurrency business Cache results of getDriverCurrentAddress, limit concurrent executions, and serialize writes with locks or serial queues.
Thread‑usage evaluation and remediation Only spawn threads for tasks that are time‑uncertain, CPU‑intensive, or could block the main thread; avoid unnecessary threads.
Deadlock detection and fixing Identify stack traces containing psynch cvwait/semwait, mutexwait, dispatch_sync slow, etc., and adjust locking or priority inversion.
UI‑thread enforcement Use Xcode’s Main Thread Checker and runtime logs to catch UI updates on background threads.
Long‑Term Mechanism
Establish thread‑count monitoring using pthread introspection hooks:
typedef void (*pthread_introspection_hook_t)(unsigned int event, pthread_t thread, void *addr, size_t size);
enum { PTHREAD_INTROSPECTION_THREAD_CREATE = 1, PTHREAD_INTROSPECTION_THREAD_START, PTHREAD_INTROSPECTION_THREAD_TERMINATE, PTHREAD_INTROSPECTION_THREAD_DESTROY };
void pthread_introspection_hook_t(unsigned int event, pthread_t thread, void *addr, size_t size) { if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) { /* increment count */ } else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) { /* decrement count */ } }When thread count exceeds a configurable threshold, emit warnings in debug and later report via APM.
Review & Summary
Since April, the solution has reduced crash count by ~8 ‰ (≈26 k crashes) and lowered average thread count from 51.3 to 41.6, saving ~18.7 % CPU resources.
The practice demonstrates how systematic queue management, concurrency control, and monitoring can dramatically improve stability and performance of a large‑scale iOS driver app.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
