Memory profiling
Skill almasumdev/awesome-mobile-performance-agent-skills/.github/skills/memory/memory-profiling
Agent skills for profiling and optimizing mobile app performance (startup, memory, frame-rate, network).
npx -y skills add almasumdev/awesome-mobile-performance-agent-skills --skill memory-profilingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Capture and analyze heap dumps on Android (Android Studio Profiler, LeakCanary) and iOS (Instruments Allocations/Leaks). Use when memory-related crashes or growth are suspected.
SKILL.md
5.5 KB, as published. Nobody here has run it
Memory Profiling
Instructions
Memory problems on mobile manifest as low-memory kills, OutOfMemoryError, thermal throttling, or visible slowdowns after prolonged use. Profile before changing anything.
1. Budgets and Signals
| Platform | Foreground budget (p50 device) | Kill threshold |
|---|---|---|
| iOS | ≤ 200 MB resident (Xcode "Memory") | ~1.3 GB hard limit on 2 GB devices |
| Android | ≤ 250 MB PSS foreground | onTrimMemory(TRIM_MEMORY_CRITICAL) events |
Key signals to gather:
- Peak memory on cold launch and on the heaviest screen.
- Retained memory after navigating away (should return to baseline ± 5 MB).
onTrimMemoryevents (Android) anddidReceiveMemoryWarning(iOS) frequency.- Production: MetricKit
MXMemoryMetricand Firebase Performancememorytraces.
2. Android — Android Studio Profiler
- Android Studio → Profiler → select the device and process.
- Click the Memory row. You see a live chart of Java, Native, Graphics, Stack, Code, and Other.
- Force GC (trash icon) before capturing. Otherwise garbage skews the picture.
- Click Dump Java heap to capture a
.hprof. - Filter by Allocated in range to see only objects created during a specific action.
- Right-click a class → Go to Instance → inspect References tab for retention path.
Look for:
- Large bitmap retention under
android.graphics.Bitmap(seebitmap-and-image-optimization). - Duplicate
Activityinstances — classic leak signal. - Unbounded
HashMap/ArrayListin singletons.
3. Android — LeakCanary
Add in debug:
dependencies {
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.14")
}
LeakCanary watches for retained Activity, Fragment, View, and ViewModel. When one fails to be collected after the expected lifecycle event, it dumps the heap and prints a leak trace:
GC Root: Thread object
...
* leaks com.example.FeedActivity instance
The offending reference chain pinpoints the fix.
4. iOS — Instruments Allocations + Leaks
- Product → Profile → Leaks template (bundles Allocations).
- Run the interaction that you suspect grows memory.
- Use Mark Generation before and after the interaction. A generation is the set of objects allocated in that window. If the generation's persistent bytes > 0 after the action unwinds, you have retained objects.
- Leaks track shows cycle retention detected automatically.
- For ARC retain cycles that Leaks does not detect (e.g.,
DispatchQueueholding a closure), inspect the generation by class and look for types that should have been deallocated.
class FeedViewModel {
var onUpdate: (() -> Void)?
func subscribe() {
Store.shared.observe { [weak self] in // NOT self. strong = cycle
self?.onUpdate?()
}
}
}
5. Flutter — DevTools Memory View
- Run
flutter run --profile. - DevTools → Memory → click GC → Take heap snapshot.
- Use Diff Snapshots between two navigation round-trips. Any class whose instance count grew and did not return to zero is leaking.
- Filter by
runtimeTypeof your widgets — a State whose count keeps growing is a leak.
Tool: leak_tracker package for CI.
void main() {
LeakTracking.start();
runApp(const MyApp());
}
6. React Native — Chrome / Hermes Heap Snapshot
Hermes supports .heapsnapshot via:
import { DevSettings, NativeModules } from 'react-native';
NativeModules.HermesExecutorFactory.takeHeapSnapshot('/sdcard/app.heapsnapshot');
Open in Chrome DevTools → Memory → Load. Compare two snapshots ("Comparison" mode). Look at:
- Closures (compiled functions) retaining large scopes.
- Event emitter listeners that were added but never removed.
7. Reading a Retention Path
The fix pattern is always the same: the root is GC-reachable (thread, static, subscription), and it references your object through some chain. Break the chain closest to the leaf:
- If a singleton holds the leaked object → clear the reference on
onDestroy/deinit. - If a listener list → unsubscribe in
onDispose/deinit/dispose. - If a thread / coroutine → cancel on scope exit (
viewModelScope,Task { }.cancel(),StreamSubscription.cancel).
8. Native Memory on Android
Java heap is only part of the story. dumpsys meminfo and Android Studio's Native Memory track cover NDK libraries, Skia buffers, MediaCodec.
adb shell dumpsys meminfo com.example.app
Watch the Graphics row — large values usually mean retained Surfaces, textures, or video decoders.
Checklist
- Baseline memory captured in release/profile on a p50 device.
- Heap snapshot taken before and after a suspect navigation flow.
- Retention paths traced to a specific owner and documented in PR.
- LeakCanary (Android) wired in debug builds; crashes pager for retained
Activity/Fragment. - iOS generation diff shows no unexpected persistent objects after screen teardown.
- Flutter
leak_trackerintegrated in integration tests. - MetricKit / Firebase Performance memory traces feeding a dashboard.