Memory and device evidence

Find Memory Leaks Across Repeated On-Device Inference

Repeat one fixed task and inspect whether owned memory returns after each lifecycle.

Review status: Fact and editorial QA complete; owner review pending · 2026-10-03 · Fact IDs: MEMORY-03, COVE-LIFECYCLE-01

Direct answer

A rising memory graph during repeated inference is a signal to investigate, not by itself proof of a leak. The graph may include normal caches, delayed garbage collection, retained conversation history, native tensors, image buffers, or objects still owned by an active task. A useful leak test repeats the same bounded workload, captures memory at the same lifecycle checkpoints, closes the engine and conversation through their owners, allows the app to settle, and compares retained instances rather than relying on a single peak. Android Studio heap dumps help inspect managed objects; a managed heap view does not account for every native allocation. Choose one workload and make it repeatable: same model artifact, prompt shape, output limit, image dimensions or audio length, backend request, and number of turns. Measure a baseline before load, after load, at the task peak, after output is discarded, after conversation close, and after engine close. If memory returns only after process restart, that is a clue about ownership or allocator retention, not sufficient proof of the exact leaking object. Keep Java heap, process RSS, native heap, GPU allocation, and file cache separate if the tools expose them. The investigation should ask whether object count grows with each cycle, whether the same activity or context remains reachable, whether an observer or coroutine retains a view model, whether stream collectors survive cancellation, whether camera ImageProxy objects close, and whether the native engine is closed exactly once. Capture a heap dump after a warm-up cycle and after several identical cycles. Compare retained object types and reference paths. Then change one cleanup boundary and repeat. A one-time allocation that stabilizes may be a cache; unbounded retained task objects suggest a lifetime bug. Do not publish memory-growth numbers unless the device, build, tool, metric, and raw run sequence are recorded. Test the lifecycle, not only the inference call. Rotate the device, navigate away and back, cancel mid-stream, trigger an exception, background the app, return, and repeat the task. Use one owner for engine creation and close; ensure every branch, including initialization failure, reaches a cleanup path. Ensure stale results cannot keep an entire screen tree alive. When diagnosing a camera-to-model path, release the camera frame even if inference throws. When diagnosing audio, release recorder buffers and close streams after finalization. A safe report separates observations from conclusions: “managed heap returned near the measured baseline after close,” “native memory was not observable with this tool,” or “activity instance remained reachable through this reference path.” Do not say “fixed a leak” until the same repeated test no longer shows the retained object path and the task still succeeds. This is an engineering validation guide, not a Cove benchmark result. Protocol: 1. Define the repeatable task and a fixed number of cycles; pin app build, model artifact, runtime, device, OS, prompt or media fixture, and output limit. 2. Capture heap and process observations at named lifecycle checkpoints using the tool appropriate to each memory layer. Save the test sequence and avoid real personal content. 3. Inspect retained instances and reference paths after engine and conversation close; check coroutine jobs, observers, activity/context references, buffers, and native-resource owners. 4. Change one owner or cleanup path and rerun the same sequence, including cancellation, exception, rotation, and reopen. 5. State what the evidence can and cannot establish; preserve unmeasured native, GPU, and allocator behavior as unknown. The outcome is a bounded, reproducible diagnosis—not a generic claim that all local AI sessions leak or that one cleanup call solves every runtime.

Memory rises after each repeated translation session

A tester runs the same short local translation many times, navigates between screens, and notices memory usage trending upward. A single screenshot cannot tell whether the model cache is stable, a coroutine remains active, a conversation is retained, or a native allocation is expected.

Decision

Repeat the same workload with named checkpoints, compare retained object references after close, and alter one lifecycle owner at a time.

Expected outcome

The team obtains a testable explanation and a regression case without mistaking one memory peak for a verified leak.

Evidence to collect

The claim becomes reviewable only when the following evidence is attached to the same artifact and test run:

  • Ordered memory series
  • Close and cancellation points
  • Post-run baseline

A device badge must come from an exact device, OS, artifact, runtime, backend, and workload record, not parameter-count intuition.

Implementation workflow

  1. Freeze the repeated workload. Use the same app build, artifact, runtime, backend request, prompt and output limits, media dimensions, and cycle count. Separate one warm-up from measured cycles and do not mix unrelated screens or tasks.
  2. Capture comparable lifecycle checkpoints. Measure baseline, after model load, task peak, after discarding output, after conversation close, and after engine close. Label heap and process metrics distinctly, and note when garbage collection or settling was allowed.
  3. Follow retained references. Compare heap dumps for activity, context, view model, listener, collector, image, audio, and conversation objects that remain reachable. Determine which owner holds each object and whether the reference is expected to survive the screen.
  4. Fix one cleanup path and rerun stress cases. Change one owner or close path, then rerun the same cycle sequence with cancellation, exception, rotation, navigation, and reopen. Verify task output still passes before describing the suspected retention as resolved.

Keep each transition observable. A failure should identify the stage, artifact, runtime, and recovery action without logging private user content.

Acceptance criteria

  • The evidence records artifact, app build, runtime, device, workload, and exact memory metric.
  • A claimed leak has a retained object or allocation path that grows across identical cycles and is tied to an owner.
  • After a cleanup change, the repeated task still succeeds and the previously observed reference path is no longer retained.

Decision table

DimensionChoice or evidenceHow to interpret it
One-time warm-up increasePossible cache or initialization costNeeds repeated checkpoints; one higher sample is not a leak diagnosis.
Managed object retained after closeHeap reference-path investigationHeap dump can identify Java/Kotlin reachability and lifecycle ownership.
Native or GPU memory does not fallProcess/runtime allocation investigationManaged heap tools alone may not explain native or driver allocations.

Failure patterns to prevent

  • Looking only at the first run
  • Forcing process exit as cleanup

Also prevent silent fallback, unpinned artifacts, missing cancellation, and conclusions that combine unlike configurations. Store unsuccessful runs alongside successful ones.

Minimum reproducibility record

LayerRecord
DeviceManufacturer, model, chipset, RAM class, operating-system build
SoftwareApplication version and git commit
ModelFamily, variant, revision, format, file length, hash, quantization
RuntimeName, revision, requested backend, observed backend evidence
WorkloadFixture revision, input hash, prompt hash, output policy
OutcomeCompleted, failed, cancelled, fallback, and privacy-safe diagnostics

Release checklist

  • ☐ The primary query is answered without an unsupported number.
  • ☐ Every artifact and runtime is pinned.
  • ☐ The representative task and failure policy are explicit.
  • ☐ Lifecycle, cancellation, cleanup, and fallback are tested.
  • ☐ User-content and network boundaries are documented.
  • ☐ Result wording applies only to the recorded configuration.
  • ☐ The page links to raw method or evidence when results are added.

Sources and related evidence

Chinese deployment and troubleshooting content is organized in the .奇连 AI 端侧专题.

Frequently asked questions

Does memory that stays high after one request prove a leak?

No. Caches and allocators may retain memory for reuse, and garbage collection may be delayed. Repeat a fixed task, compare retained instances after close, and separate process memory from managed heap.

Why take heap dumps after several sessions?

A retained activity, listener, collector, or conversation may only become clear after repeated lifecycle cycles. Comparing object counts and reference paths across consistent checkpoints is more informative than a single snapshot.

Can a heap dump confirm a native engine leak?

Not by itself. Heap dumps analyze managed objects. Native engine, GPU, and allocator behavior may need separate process or runtime diagnostics and should remain an explicit unknown if not measurable.