with one click
java-memory-leaks
// How to identify and fix Java memory leaks in Android Chrome using LeakCanary traces.
// How to identify and fix Java memory leaks in Android Chrome using LeakCanary traces.
Add missing LINT.IfChange(...) / LINT.ThenChange(...) guards to enums in C++/Java and XML to keep them in sync. Trigger this skill ONLY when a contributor explicitly asks to add lint guards or synchronize enums using LINT guards.
Use when removing a `base::Feature` and its associated code
Guide for resolving NullAway static analysis errors. Best practices for: - Passing ObservableSupplier/Supplier<@Nullable T> - Dereferencing potentially @Nullable values - Adding @NullMarked to Java code
Identify and safely remove expired Chromium histograms (dead metrics/technical debt). Use this skill when a contributor asks to clean up metrics, fix code health issues related to histograms, remove obsolete code, or work on a histogram cleanup task.
Orchestrator for the "Code Health Hub" framework. Trigger only when the user refers to the Hub or asks to see "available cleanup tasks" within the Chromium technical debt reduction system.
Modularize a chrome/browser/ subfolder by splitting its sources out of the monolithic //chrome/browser:browser target into dedicated source_set targets in the subfolder's own BUILD.gn. Use when the user asks to modularize, extract, or create BUILD targets for a chrome/browser/ subfolder, or mentions "Project Bedrock", "//chrome/browser modularization", or wants to split a subfolder into header/impl/test targets. Also use when the user says "modularize chrome/browser/X" for any X.
| name | java-memory-leaks |
| description | How to identify and fix Java memory leaks in Android Chrome using LeakCanary traces. |
This skill guides the process of identifying, debugging, and fixing Java memory leaks in Android Chrome, typically identified by LeakCanary in instrumentation tests.
Confirm the Leak:
@DoNotBatch). Batched
tests can share state and make leak traces ambiguous or hard to reproduce.@EnableLeakChecks or
else LeakCanary will not run.Analyze Leak Trace:
Leaking: YES).Leaking: UNKNOWN nodes in between to find where the chain should
be broken.Identify the Break Point:
destroy() on components that hold resources or
observers.Apply Fix Patterns:
removeObserver() is called in onDestroy() or equivalent lifecycle
teardown.DestroyObserver, consider making it one and
registering it with ActivityLifecycleDispatcher.onDestroy().@Nullable and add explicit
null checks where needed. This is safer and satisfies NullAway without
suppressions.@Nullable causes too
much "collateral damage" (requiring null checks in many places), you can
use @SuppressWarnings("NullAway") on the onDestroy() method to set
the field to null while keeping it non-null for the rest of the
lifecycle.private @Nullable CustomTabActivityTabProvider mTabProvider;
@Override
public void onDestroy() {
mTabProvider = null; // Breaks leak trace
}
removeTab()), ensure
this is done by the owner of the component, not by an observer or
registrar. Observers should not have side effects that mutate the
observed object during teardown.Verify:
autoninja -C out/Debug chrome_public_test_apk.out/Debug/bin/run_chrome_public_test_apk -f "YourLeakTest*".onDestroy() can cause
NullPointerExceptions if other components try to use them during their own
destruction (e.g., to unregister observers). Ensure that cleanup methods like
unregisterObserver handle null references gracefully.
public void unregisterActivityTabObserver(CustomTabTabObserver observer) {
mActivityTabObservers.removeObserver(observer);
if (mTabProvider == null) return; // Guard against NPE during destruction
Tab activeTab = mTabProvider.getTab();
...
}
Before:
public class MyComponent implements DestroyObserver {
private final LongLivedProvider mProvider; // Retains activity
public MyComponent(LongLivedProvider provider) {
mProvider = provider;
}
@Override
public void onDestroy() {
// Provider still holds reference to this component, leaking activity
}
}
After (Preferred):
public class MyComponent implements DestroyObserver {
private @Nullable LongLivedProvider mProvider;
public MyComponent(LongLivedProvider provider) {
mProvider = provider;
}
@Override
public void onDestroy() {
if (mProvider != null) {
mProvider.removeObserver(this); // If applicable
mProvider = null; // Break the leak chain
}
}
}