Mobile Development 13 min read

Analyzing Native Memory OOM in Android Camera Implementations and Effective Mitigation Strategies

This article investigates native memory out‑of‑memory crashes on certain Android devices caused by excessive CameraMetadata allocations, explains how delayed finalization and GC timing exacerbate the issue, and proposes proactive memory release and GC triggering techniques that dramatically reduce crash rates.

Watermelon Video Tech Team
Watermelon Video Tech Team
Watermelon Video Tech Team
Analyzing Native Memory OOM in Android Camera Implementations and Effective Mitigation Strategies

The article examines native memory OOM problems encountered on specific Android devices during camera usage, leveraging the Raphael native memory monitoring tool and memory snapshot analysis to uncover the root causes.

Background: Large numbers of crashes were observed on Douyin versions 7.8.0‑8.3.0, with over 60% of native crashes related to camera memory leaks, especially on OPPO devices where native crashes were three times higher.

Problem: Monitoring data showed native memory reaching ~1.3 GB (near the 2 GB limit on 32‑bit processes) at OOM, with CameraMetaData objects accounting for the majority of the leak.

Initial Analysis: CameraMetaData creation originates from Java calls that allocate native memory via boot‑framework.oat and libandroid_runtime.so. Each CameraMetaData instance owns a distinct camera_metadata_t buffer, and the release logic mistakenly transfers ownership instead of freeing it, leading to accumulation.

Searches in the AOSP source revealed that both creation and deletion of CameraMetaData occur in android_hardware_camera2_CameraMetadata.cpp , with the native close method invoked from the Java finalize path.

During OOM events, many CameraMetadataNative objects remained in the FinalizerDaemon queue awaiting finalization, confirming that delayed finalization contributed to the memory pressure.

Deep Analysis: The investigation ruled out finalize‑timeout exceptions; instead, the FinalizerDaemon thread was blocked on queue.remove() when no objects were queued, which only unblocked after a GC cycle. The periodic GC triggered by heap dumps caused a sudden influx of pending finalizations, overwhelming native memory.

Because the camera page continuously creates CameraMetadataNative objects (≈30 times/s) while the Java heap remains low, the ART GC does not run frequently enough. Consequently, native memory grows unchecked until the next GC, at which point the accumulated allocations exceed the virtual memory limit and cause OOM.

Solution: Rather than forcing frequent GC (which harms performance), the team introduced an explicit release strategy: after using a CameraMetadataNative object, invoke its close method via reflection to free the associated native buffer immediately. Experiments showed a substantial reduction in native memory growth and eliminated the OOM crashes.

Post‑deployment metrics confirmed that crashes where Java & Native memory accounted for >15% of total crashes dropped to near zero, and CameraMetadata native usage stayed below 2 MB.

Conclusion: The root cause was delayed finalization due to infrequent GC, leading to native memory buildup from CameraMetadataNative objects. Proactive native buffer release and careful GC tuning are essential for stable Android camera implementations, and reliance on Java finalizers for native memory cleanup is discouraged.

AndroidGarbage CollectionCameraoommemory-monitoringNative Memory
Watermelon Video Tech Team
Written by

Watermelon Video Tech Team

Technical practice sharing from Watermelon Video

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.