Debugging Android Chrome Memory over USB

Android is the platform where the same V8 engine you profile on the desktop runs against a fraction of the memory, so it is the fastest way to find out which of your leaks actually matter. This page belongs to remote debugging memory on mobile browsers inside Browser DevTools & Performance Profiling Workflows.

Symptom Root Cause Immediate Action
Device listed as unauthorized Authorisation prompt not accepted Reconnect and accept on the device screen
No tabs under chrome://inspect Discovery off, or the device is asleep Enable USB debugging and wake the screen
Capture takes several seconds and drops frames Snapshot cost scales with device speed Expect 3–5 s; drain interaction first
Trace goes flat halfway through Screen locked, timers throttled Keep the screen awake for the whole capture
Numbers do not match the desktop run Different limits, pixel ratio and decode sizes Compare structure, not absolute figures

Root Cause: Same Engine, Different Budget and Different Interruptions

Android Chrome runs the same V8 you profile locally, which is the good news: retainer chains, constructor names and snapshot semantics are identical, and everything you know from a desktop heap snapshot transfers directly.

What differs is everything around the engine. The heap ceiling is set from device memory and is often a quarter of a desktop’s. Image decodes are larger because the device pixel ratio is higher, so the same gallery holds more bitmap memory. And the browser is a guest of the operating system: background tabs are frozen, timers throttled, and under pressure the renderer is discarded outright.

Those interruptions are what make mobile recordings hard to trust. A trace that flatlines for eight seconds usually means the screen locked, not that allocation stopped. A recording that ends abruptly usually means the tab was discarded. Neither shows up as an error in the DevTools UI, which is why the discipline is: screen awake, cable connected, short focused flows.

The capture cost is the last practical constraint. Walking the object graph is proportional to heap size and to memory bandwidth, so a snapshot that takes 900 ms on a laptop takes three to five seconds on a mid-range phone, with the page frozen throughout. Capture at a quiet moment, not in the middle of an animation.

The Android inspection chain and its constraints Chrome on the device exposes a debugging socket, adb forwards it over USB, and desktop DevTools attaches to it. Three device-side constraints are listed alongside: a smaller heap ceiling, a higher device pixel ratio inflating decodes, and system-level freezing and eviction. Same V8, three constraints that only exist on the device Chrome on Android USB debugging on debug socket exposed adb over USB adb devices → device port forwarded to the host chrome://inspect full DevTools, desktop UI Memory tab included smaller heap ceiling derived from device memory, often a quarter of desktop's higher pixel ratio decodes and canvases cost 4–9× the desktop equivalent freezing and eviction a locked screen throttles timers; pressure discards the tab entirely

Step-by-Step Fix

  1. Authorise the device. Command: adb devices. Expected: R3CT90BCXXX deviceunauthorized means the on-device prompt was not accepted.
  2. Open the target list. Path: chrome://inspect/#devices → Inspect. Expected: a DevTools window bound to the device tab, with the Memory tab available.
  3. Quiesce before capturing. Stop animations and polling, and let the page idle for a few seconds. Expected: a flat memory counter before the capture starts.
  4. Capture with the screen awake. Path: Memory → Heap snapshot → Take snapshot. Expected: 3–5 seconds of frozen page on a mid-range device.
  5. Save and analyse on the desktop. Verification: the retainer chain in the saved file matches what you see in a desktop run of the same flow, confirming an application-level rather than device-level cause.

Command & Code Reference

Getting the device connected and confirming what you are actually profiling.

# 1. Is the device visible and authorised?
adb devices -l
# Expected: R3CT90BCXXX  device product:... model:SM_G991B

# 2. Which Chrome build is on the device? Version differences change heap
#    limits and default flags, so record this with the measurement.
adb shell dumpsys package com.android.chrome | grep versionName

# 3. What memory class does Android assign the device? This drives the
#    heap ceiling Chrome chooses.
adb shell getprop dalvik.vm.heapgrowthlimit
adb shell cat /proc/meminfo | head -3

Keeping the screen awake for the length of a capture, which removes the most common source of a corrupted recording.

# Stay awake while charging over USB — the setting the DevTools docs assume.
adb shell settings put global stay_on_while_plugged_in 3

# Verify it took effect (3 = AC + USB + wireless).
adb shell settings get global stay_on_while_plugged_in

# Restore afterwards so the device behaves normally again.
# adb shell settings put global stay_on_while_plugged_in 0

Capturing the device’s own heap limits from the page, so the numbers can be compared honestly against a desktop run.

// Run this in the DevTools console attached to the device tab.
// jsHeapSizeLimit is what V8 chose for THIS device, and it is usually
// far below the desktop value that a local run reported.
const m = performance.memory;   // requires --enable-precise-memory-info for exact values
console.log({
  usedMb: (m.usedJSHeapSize / 1048576).toFixed(1),
  totalMb: (m.totalJSHeapSize / 1048576).toFixed(1),
  limitMb: (m.jsHeapSizeLimit / 1048576).toFixed(1),
  dpr: window.devicePixelRatio,          // drives decode and canvas cost
});
The same leak on two devices The same per-interaction leak is measured on desktop and on a mid-range Android phone. On desktop the heap reaches four hundred megabytes after fifty interactions without approaching its limit. On the phone the tab is discarded after seventeen interactions, because the ceiling is a quarter of the size and decodes cost more. Identical application code, identical leak, different consequences 0 1 GB 2 GB interactions (0 → 50) desktop limit ~2 GB device allowance ~380 MB desktop: 400 MB after 50, no limit reached tab discarded at interaction 17 The desktop run would never have found this; the structure it shows in a snapshot is nevertheless the same one.

Verification & Regression Prevention

Verify the fix on the device, because the device is where the budget bites, but do the analysis on a saved snapshot at the desk. Opening a 200 MB snapshot in DevTools while it is still attached to a memory-constrained phone is a good way to lose the tab you were measuring.

For prevention, add the device’s own numbers — jsHeapSizeLimit and devicePixelRatio — to whatever telemetry you already collect from real sessions. Those two values explain most of the difference between “fine in testing” and “crashes for a segment of users”, and having them broken down by device class turns an anecdote into a target: if the 95th-percentile session on a ratio-3 device peaks at 80% of its allowance, that is a number a team can work against.

Five conditions for a capture worth trusting Screen awake for the whole capture, cable rather than wireless, animations and polling stopped, capture taken after a forced collection, and the snapshot saved and analysed on the desktop. Each condition is paired with the failure it prevents. Miss any one of these and the capture may quietly be fiction Screen awake throughout prevents: a flat stretch of trace that is throttling, not application behaviour Cable, not wireless, for captures prevents: losing a five-second snapshot to a dropped connection Animations and polling stopped prevents: measuring allocation rate instead of retention Capture after a collection prevents: counting garbage that the next scavenge would have removed Analyse the saved file on the desktop — prevents: evicting the tab you are studying

FAQ

Why does the snapshot take so much longer on a phone?

Capture cost scales with heap size and with how fast the device can walk the object graph, and a phone’s memory bandwidth and single-core speed are a fraction of a laptop’s. A capture that takes under a second on desktop routinely takes three to five on a mid-range Android device, during which the page is frozen.

Can I profile without a cable?

Yes, with adb over Wi-Fi, and it is convenient for short interactions. It is also less reliable for anything lasting more than a few seconds, because a dropped connection during a capture loses the whole snapshot. Use the cable for captures and wireless for quick inspection.

Do desktop numbers translate to the device?

The retention structure translates — the same object holds the same chain — but the absolute figures do not. Heap limits, device pixel ratio, image decode sizes and the eviction threshold all differ, so a leak that costs 20 MB on desktop can cost far more on a phone with a higher pixel ratio and a smaller allowance.