Expert Opinions and Insights from the Tech Industry

September 23, 2026

For years, the Android development community has approached memory optimization with a reactive mindset, addressing issues only when applications exhibit crashes, slowdowns, or erratic behavior on lower-end devices. This practice is increasingly difficult to justify, especially in light of recent developments.

In August 2026, Google Play unveiled new performance requirements that focus on dynamic memory usage, bitmap memory, and DEX code optimization. With enforcement set to commence in February 2027, applications that exceed these thresholds may face diminished visibility and publishing capabilities on the platform.

However, the most significant change for engineering teams extends beyond the impending deadline. Memory usage has now become a critical factor that can impede a release, even in cases where developers cannot replicate a crash locally. This evolution necessitates treating memory metrics with the same importance as startup time, ANR rates, and binary size—integrating them into the pre-production process.

What Google Play is measuring

Google’s new requirements categorize memory into distinct areas rather than presenting it as a singular heap-size figure, a much-needed clarification.

  • Dynamic memory usage: This metric encompasses anonymous RSS plus swap, which includes private memory utilized by the application—both active and compressed—while excluding file-backed data like code and assets. Google Play intends to assess this across various application states and device performance categories.
  • Bitmap memory: Google is scrutinizing whether applications retain bitmaps that are no longer visible. While retaining a large image in memory during active screen usage is acceptable, maintaining a collection of those images after the application transitions to the background presents a different challenge.
  • DEX optimization: Apps distributed via Play must achieve at least 25% coverage in optimization, shrinking, and obfuscation using tools like R8. This requirement aligns with the goal of achieving a smaller memory footprint, quicker startup times, fewer ANRs, and improved runtime performance.

The key takeaway is that these measurements are contextual. A single memory figure recorded on a developer’s personal device offers limited insight into how an application performs across varying RAM capacities, process states, and user interactions.

Why memory problems are difficult to reproduce

Dynamic memory usage is assessed as anonymous RSS plus swap, covering private memory utilized by the application while excluding file-backed data. Google Play plans to evaluate this across different application states and device performance categories.

Bitmap memory is another focal point, with Google examining whether applications retain bitmaps when they are no longer visible. Retaining a large image while its screen is active is acceptable; however, retaining multiple images after the application moves to the background is a concern.

Regarding DEX optimization, Play-distributed apps will need to achieve at least 25% coverage across optimization, shrinking, and obfuscation using R8 or similar tools. This requirement is crucial as DEX optimization correlates directly with a reduced memory footprint and enhanced performance.

It is essential to note that these measurements are contextual. A single memory figure from a developer’s device does not accurately reflect an application’s behavior across various RAM categories, process states, and user flows.

Investigating memory growth

To practically investigate memory growth, I recommend starting with Android Studio’s Memory Profiler. Instead of immediately searching for the largest object in the heap, reproduce a specific user flow multiple times. For instance:

  1. Feed → Product → Gallery → Back → Feed

Monitor memory changes after each iteration and following garbage collection. If memory consistently rises during the gallery phase and then stabilizes near the original baseline, this likely indicates temporary allocations. Conversely, if the baseline continues to rise, it may be time to conduct a heap dump.

Upon examining a heap dump, discovering multiple instances of a Fragment that should have been destroyed is just the beginning. The critical inquiry is not merely whether those objects consume significant memory but rather what they retain.

A Fragment may retain its view hierarchy, which in turn retains an ImageView that references a decoded bitmap. This seemingly minor lifecycle leak can lead to several megabytes of image memory being held unnecessarily. Therefore, I focus on reference paths rather than raw object counts, aiming to uncover why an object remains reachable from a GC root after its lifecycle should have concluded.

Tools like LeakCanary, now integrated into Android Studio Quail 2’s Profiler, can expedite the investigation of lifecycle-related leaks. For broader analysis, I utilize Perfetto, which offers system-level context when a heap dump alone falls short.

Investigating Retained State: The Gallery Issue

During thorough architectural reviews, I often encounter issues related to retained state. Quality Assurance may not report crashes, but repeated gallery sessions can reveal a gradual increase in memory consumption.

The instinct is frequently to attribute this to the image loader’s cache. While disabling caching might mitigate memory growth, it rarely resolves the issue entirely. A heap dump taken after closing the gallery often reveals that an object linked to the gallery remains reachable. Tracing the reference chain typically uncovers a long-lived component holding a callback created by the screen, which captures state that ultimately references the image data.

Addressing this requires rectifying the ownership or lifecycle of that callback, rather than merely reducing cache size. This distinction is crucial, as cache tuning can obscure a leak without providing a genuine fix. I advise teams to approach this from behavior to ownership: identify a repeatable flow, determine whether the baseline grows, inspect retained objects, and only then decide on the necessary architectural adjustments.

Bitmap memory deserves its own investigation

I emphasize to my teams the importance of scrutinizing images, as compressed file size is a poor indicator of runtime cost. A JPEG that occupies a few hundred kilobytes on disk can easily expand to several megabytes once decoded. Bitmap memory is contingent on pixel dimensions and format, not merely download size.

A common misstep is decoding an image that is significantly larger than what the UI requires. A 4000 × 3000 image does not need to maintain that resolution to serve as a small thumbnail. While modern image-loading libraries manage much of this, it remains essential to understand their configuration and caching behavior. Following Google’s guidance, downsampling images to match UI dimensions is imperative.

Retaining a large bitmap while the user actively views it is perfectly acceptable. However, if that same bitmap persists after its screen disappears or while the application is in a cached process state, it warrants immediate investigation. This is why I advocate for contextual measurements rather than blanket rules, such as “the app must never exceed 300 MB.”

Move memory checks before production

The Play Console and Android vitals have become invaluable resources for real-world memory insights. Google is enhancing dynamic-memory and bitmap-memory metrics, providing breakdowns by percentile and RAM bucket, filtering OOM-related terminations, and offering DEX optimization insights along with proactive warnings.

However, I firmly believe that production telemetry should serve as a final line of detection rather than the initial one. We must begin defining representative memory scenarios for each release candidate, including:

  • Cold launch and idle
  • Navigation through high-traffic flows
  • Image-heavy flows
  • Repeated entry and exit of complex screens
  • Foreground-to-background transitions

The critical aspect is repeatability. The same flow should run on identical device categories or emulator configurations to enable comparison against previous builds. If a checkout flow historically stabilizes around 170–190 MB, and a new release candidate reaches 240 MB, that regression necessitates investigation before deployment, even if both figures remain below platform thresholds.

Build a memory budget instead of waiting for an OOM

Rather than waiting for crashes, I advocate for establishing a strict memory budget. Set a baseline after startup, an acceptable peak while opening a media-heavy screen, and an expected post-navigation baseline after that screen closes. These figures should be derived from actual measurements across representative devices, rather than being borrowed from other applications.

This focused approach helps avoid the pitfall of indiscriminately optimizing every allocation. If memory temporarily rises during a complex operation and subsequently returns to baseline, there may be nothing to address. However, if a release introduces an additional 30 MB of retained memory every time a user repeats a common flow, it should be addressed long before an OutOfMemoryError arises in production.

Over time, these checks will naturally integrate into performance regression testing. Your CI doesn’t need to automatically diagnose the leak; simply detecting that a benchmarked flow now consumes significantly more memory provides engineers with the signal to inspect the build prior to shipping.

A short pre-release memory checklist:

  1. Run important user flows repeatedly and compare the post-flow baseline, not just the peak.
  2. Test on devices beyond just high-memory flagship models.
  3. Take a heap dump when memory remains elevated and inspect retention paths.
  4. Examine image dimensions, decoding configurations, and cache behavior on bitmap-heavy screens.
  5. Test transitions between foreground, background, and cached states.
  6. Review R8 optimization instead of assuming that enabling R8 guarantees application optimization.
  7. Compare memory measurements with previous releases and investigate significant regressions.
  8. Check Android vitals and Play Console warnings rather than waiting for user-reported OOM crashes.
AppWizard
Expert Opinions and Insights from the Tech Industry