Potential Memory Leaks
96 concrete memory-leak risk patterns identified by static analysis: Handler / Runnable callbacks not cancelled, WebViews not destroyed, Coroutine Jobs not tracked, static Fragment references, listener/observer/receiver registration without unregister, and bitmap/cursor/animator resources not released.
Leak patterns at a glance
Findings by leak type
Severity distribution
What each pattern means
| Pattern | Why it leaks | How to fix |
|---|---|---|
| HANDLER_LEAK | Anonymous Handler/Runnable/postDelayed retains an implicit reference to the enclosing Activity/Fragment. Pending callbacks survive destroy. | Static Handler + WeakReference, or migrate to lifecycleScope.launch { delay() }; always removeCallbacksAndMessages(null) in onDestroyView/onDestroy. |
| WEBVIEW | WebView holds a large native context (tab, GPU surface). Not calling destroy() leaks the renderer process. | webView.destroy() in onDestroyView; null out the field; never store WebView in a ViewModel or static. |
| COROUTINE_JOB | A coroutine launched from a custom CoroutineScope without storing the Job can outlive its component, holding callbacks alive. | Inside fragments, use viewLifecycleOwner.lifecycleScope. In helpers, accept the scope from the caller; never own one. |
| FRAGMENT_RETAIN | A static field referencing a Fragment singleton survives orientation changes and prevents the activity hierarchy from being garbage-collected. | Remove the static field; use FragmentManager.findFragmentByTag for lookup. |
| RECEIVER_NO_UNREG / OBSERVER_NO_UNREG / LISTENER_NO_UNREG | System-level callbacks (BroadcastReceiver, ContentObserver, location, sensor) keep the registrar alive until unregister. | Pair every register with an unregister in the matching teardown lifecycle method. |
| NETWORK_CALLBACK | Same: ConnectivityManager.registerNetworkCallback survives until unregisterNetworkCallback. | Unregister in onDestroyView. |
| ANIMATOR | ObjectAnimator/ValueAnimator held by the view system continue running and retain target views. | Track animators in a list; cancel() all in onDetachedFromWindow. |
| RUNNABLE | view.postDelayed(runnable) without removeCallbacks leaks the runnable + view chain. | Pair every postDelayed with removeCallbacks in onDestroyView. |
| INNER_CLASS_LEAK | A non-static inner class implicitly holds a reference to its outer class. Combined with long-lived containers (Handler, Runnable, BroadcastReceiver), this leaks the activity/fragment. | Make the inner class static; pass dependencies via WeakReference. |
| ADAPTER_CTX | Adapters / custom views holding a long-lived Activity context (instead of applicationContext) outlive the activity. | Use @ApplicationContext for any field-level reference where you only need to inflate. |
| BITMAP | Static Bitmap fields and undecoded BitmapFactory.decodeResource outputs hold native pixel buffers. | Move to instance scope; recycle() when no longer needed (or use Coil's lifecycle-aware loading). |
| RESOURCE_NO_RELEASE | Cursor, MediaPlayer, Camera etc. hold native resources until explicitly closed. | Use try-with-resources or use { }; close in matching teardown. |
| SUBSCRIPTION | RxJava subscriptions / Flow collections that keep references via captured state. | Use CompositeDisposable.clear() in onDestroy; for Flow use repeatOnLifecycle. |
Hot files
The 5 files with the most memory-leak findings — start here.
6 findings
Costco/src/main/java/com/costco/app/android/ui/main/MainActivity.java
6 findings
Costco/src/main/java/com/costco/app/android/ui/main/MainWebViewFragment.kt
6 findings
Costco/src/main/java/com/mobeta/android/dslv/ResourceDragSortCursorAdapter.java
4 findings
Costco/src/main/java/com/costco/app/android/ui/pharmacy/PharmacyWebViewFragment.kt
4 findings
Costco/src/main/java/com/costco/app/android/ui/findastore/map/FindAStoreFragment.java