How to Diagnose and Fix OOM Crashes Caused by Thread Pool Misuse in Android Apps
This guide explains how to identify OutOfMemoryError crashes in Android applications caused by excessive thread‑pool creation, using tools like Android CPU Profiler, adb ps commands, and code hooks, and provides concrete steps to refactor OkHttp, RxJava, and SDK usage to prevent resource leaks.
1. Background
During development an OOM (OutOfMemoryError) crash was observed across many pages. The stack trace showed failures in thread pool creation, with the app reporting up to 1456 threads, far exceeding normal usage.
2. Investigation Methods
2.1 Android CPU Profiler
The CPU Profiler can display all created threads, their names and states, helping to locate the source of the thread explosion.
2.2 adb ps command
Using adb shell ps | grep <package> to find the process ID, then adb shell ps -T | grep <pid> to list all threads. The watch -n 1 -d 'adb shell ps -T | grep u0_a589 | wc -l' command can monitor thread count in real time.
watch -n 1 -d 'adb shell ps -T | grep u0_a589 | wc -l'2.3 Hooking Thread Creation
Using the epic library to hook Thread constructors and log stack traces when threads are created.
private void hookThread() {
DexposedBridge.hookAllConstructors(Thread.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Thread thread = (Thread) param.thisObject;
Log.d(ThreadMethodHook.TAG, "Thread: " + thread.getName() + " stack:" + Log.getStackTraceString(new Throwable()));
}
});
}2.4 Problem Confirmation
Combining crash logs and thread‑pool analysis revealed that an SDK’s OkHttp client and RxJava’s Schedulers.newThread() were repeatedly creating new threads and OkHttpClient instances, leading to uncontrolled thread growth and OOM.
// Example of creating a new OkHttpClient each request
Dispatcher dispatcher = new Dispatcher(Executors.newSingleThreadScheduledExecutor());
return new OkHttpClient.Builder().dispatcher(dispatcher).build(); Observable.create(...).subscribeOn(Schedulers.newThread())...3. Solution
Remove Schedulers.newThread() usage for logging tasks.
Reuse a single OkHttpClient instance instead of creating a new one per request.
Limit SDK calls that create thread pools by adding request‑count and time‑interval constraints.
Configure thread pools with allowCoreThreadTimeOut to let idle core threads terminate.
4. Summary
To prevent OOM caused by thread‑pool misuse in Android apps, monitor thread creation with profiling tools or adb, avoid creating new OkHttpClient or RxJava threads for each operation, centralize thread‑pool configuration, and apply timeout policies. These steps stabilize thread counts and eliminate memory leaks.
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.
