ANR & Memory Management Flashcards
PERFORMANCE › Runtime
- What are the main ANR timeout thresholds?
- Input/key dispatch blocked for 5s; foreground BroadcastReceiver.onReceive() over 10s (background 60s); foreground Service lifecycle over 20s (background 200s); startForegroundService without startForeground() within 5s.
- What fundamentally causes an ANR?
- The main (UI) thread is blocked too long to process input or component lifecycle in time. Common reasons: slow I/O or computation on the main thread, lock contention, deadlocks, or synchronous binder calls to another process.
- How do you move long work off the main thread on modern Android?
- Use Kotlin coroutines on Dispatchers.IO or Default and post results back to the main dispatcher, or WorkManager for deferrable/guaranteed work. AsyncTask is deprecated. Use StrictMode to catch accidental main-thread I/O.
- A BroadcastReceiver needs work that may exceed 10 seconds. How do you avoid an ANR?
- Don't block onReceive(). Call goAsync() to get a PendingResult, do the work on a background thread, then call finish(); or hand off to WorkManager/JobScheduler. onReceive() itself must stay short.
- Why does holding an Activity (or its Context/View) in a static field leak memory?
- The static field outlives the Activity, so after onDestroy the GC can't reclaim the Activity or its entire view tree. Use applicationContext for long-lived needs, or null out the reference.
- Why do non-static inner classes like Handlers, Runnables, or AsyncTask leak, and how do you fix it?
- A non-static inner class holds an implicit reference to its outer Activity; if its queued/running work outlives the Activity, the Activity can't be collected. Fix: make it static and hold the Activity via a WeakReference, and remove pending messages/callbacks in onDestroy.
- How do unregistered listeners or receivers cause leaks?
- Registering a listener, BroadcastReceiver, sensor, or observer (often with an Activity as callback) without unregistering keeps the subject holding the Activity reference. Always pair register in onStart/onResume with unregister in onStop/onDestroy, or use lifecycle-aware components.
- WeakReference vs SoftReference: when is each cleared?
- A WeakReference is cleared at the next GC once the referent is only weakly reachable. A SoftReference is retained until the heap is under memory pressure (just before OutOfMemoryError), making it suitable for a memory-sensitive cache.
- What causes OutOfMemoryError with bitmaps, and how do you prevent it?
- Each app has a hard heap cap; exceeding it throws OOM. Bitmaps are usually the largest objects: a 1000x1000 ARGB_8888 bitmap is ~4MB (1,000,000 px x 4 bytes). Downsample with inSampleSize or use a loader (Coil/Glide), release on onTrimMemory, and find leaks with LeakCanary or the Memory Profiler.