LeakCanary показал стек — а виноват static context: промты, которые заставляют LLM объяснить OOM в Android

Приложение падает с OutOfMemoryError в проде. Открываете LeakCanary — а там знакомый стек: MainActivity утекла через Context в каком-то Singleton. Что делать дальше, трейс не подсказывает: он показывает, кто держит ссылку, но не почему это плохо и как переписать. Вот тут LLM и становится полезной — если скормить ей трейс правильно.

Ниже — промты, которые я гоняю по реальным утечкам памяти Android. Каждый с примером трейса LeakCanary и тем, что должно вернуться в ответ.

Провал №1: скормили стек — получили пересказ стека

Типичная ошибка: кидаете в чат весь вывод LeakCanary как есть и пишете «найди утечку». LLM честно пересказывает: «Activity утекла через статическое поле». Спасибо, это и так видно.

Причина в том, что модель не знает, что именно вы хотите: диагноз, рефакторинг или тест. Разделяйте задачи.

Промт для диагноза:

Ты — Android-инженер, который чинит утечки памяти в проде. Ниже — трейс LeakCanary. Не пересказывай стек. Ответь строго по пунктам:
1) Какой объект держит ссылку на утекший и почему GC его не собирает.
2) Какая lifecycle-связь нарушена (Activity/Fragment/View/Cursor/Listener).
3) Три наиболее вероятные причины в порядке убывания вероятности.
4) Для каждой причины — как проверить её в Android Studio Memory Profiler за 2 шага.
Если данных в трейсе не хватает — перечисли, какие поля LeakCanary надо дослать.
Трейс:
────────────
└─ com.example.app.data.SessionManager.instance
└─ mContext (Context)
└─ com.example.app.ui.MainActivity
└─ mViews (View[])
────────────

Ожидаемый ответ: SessionManager — синглтон со статическим полем, держит Context Activity, поэтому вся иерархия View остаётся в памяти. Проверка: во вкладке Memory Profiler сделать heap dump, отфильтровать по MainActivity, посмотреть retained size и цепочку referrers — там будет тот же путь.

Правило, которое экономит часы Если в трейсе нет поля-держателя (только класс), не просите модель «угадать» — попросите список того, что нужно дослать. Досылать дешевле, чем чинить не ту утечку.

Провал №2: починили симптом — утечка вернулась

SessionManager хранит Context — модель предлагает передать applicationContext. Работает. Но через месяц та же Activity снова в дампе, потому что слушатель в синглтоне остался.

Чтобы не латать по одному месту, просите рефакторинг с обоснованием:

Ниже — класс с утечкой. Перепиши так, чтобы Context Activity не удерживался. Требования:
- Замени хранимый Context на applicationContext ИЛИ убери Context из полей вовсе.
- Если нужен слушатель — предложи WeakReference или явный unregister в onDestroy.
- Покажи diff в формате unified, не переписывай весь файл.
- В конце — 3 строки: что изменилось, что осталось потенциально опасным, как это закрыть.
Код:
────────────
object SessionManager {
var context: Context? = null
private val listeners = mutableListOf<SessionListener>()
fun init(ctx: Context) { context = ctx }
fun addListener(l: SessionListener) { listeners.add(l) }
}
────────────

Модель вернёт diff: context → applicationContext, listeners → WeakReference или явный removeListener. Плюс честно скажет, что applicationContext не годится, если нужен доступ к UI-ресурсам темы — тогда решение другое.

Провал №3: «на глазок» вместо воспроизводимого теста

Легко поверить, что утечка ушла, потому что «вроде не падает». Память — плохой индикатор: OOM приходит через часы нагрузки. Генерируйте reproducer-тест.

Напиши JVM-тест (Robolectric или чистый JUnit с фейками), который воспроизводит утечку:

создаём объект Activity-подобного класса, кладём его в статический держатель, обнуляем локальную ссылку,
вызываем System.gc(), проверяем через WeakReference, что объект НЕ собран.
Затем — второй тест, который проверяет, что после рефакторинга объект СОБИРАЕТСЯ.
Используй только стандартный API и JUnit. Не тяни сторонние библиотеки.

Ожидаемый результат: два теста, один красный до правки, второй зелёный после. Это и есть доказательство, что причина найдена, а не замаскирована.

Утечка — это свойство графа ссылок Тест через `WeakReference` + `System.gc()` проверяет именно граф, а не размер heap. Именно поэтому он ловит утечку в CI, где нет устройства и Memory Profiler.

Провал №4: доверились модели без проверки гипотезы

LLM может уверенно назвать причину, которой нет. Хорошая практика — заставить её сформулировать проверяемую гипотезу до правки:

Сформулируй гипотезу утечки в виде: «Если <действие>, то в Memory Profiler <наблюдение>, иначе гипотеза неверна».
Дай две такие гипотезы: одну про static context, одну про незакрытый Cursor.
Для каждой — точные шаги в Android Studio: какая вкладка, какой фильтр, на что смотреть.

Ответ должен быть в форме «поверни экран 5 раз → сделай heap dump → отфильтруй по Cursor → retained size растёт». Если шаг нельзя выполнить в интерфейсе — гипотеза плохая, переписывайте.

Что реально закрывает OOM

Не «правильный промт», а порядок: трейс → диагноз с проверкой → diff → тест → гипотеза в Profiler. LLM ускоряет каждый шаг, но пропуск любого возвращает ту же утечку через месяц.

Если хочется глубже разобраться, откуда в Android вообще берутся такие ссылки на уровне стека и корутин, посмотрите разбор Промты для Kotlin-корутин и Flow — там та же логика, но про асинхронные держатели. Подробнее — в статье «Kotlin и Android-разработка».

Следующий раз, когда LeakCanary покажет стек, не закрывайте вкладку — скормите трейс с явной задачей. Начните с промта №1 и не переходите к правке, пока не получите три гипотезы и способ проверить каждую.

← Все статьи

Спросить AI по этой статье

Задайте вопрос по этой статье — ASI Biont ответит, опираясь на её текст.

Читайте также

Цифровая гигиена за вечер: как найти утечки персональных данных и удалить информацию о себе из интернета

27 октября 2026

Сколько часов учить испанский до DELE 2026: разбор нормативов, статистики и гибридной подготовки с AI-репетитором

27 октября 2026

Юнит-тесты на Python с LLM: 12 промтов от pytest-фикстур до Hypothesis, которые закрывают непокрытые ветки

27 октября 2026

Full-Stack AI Engineer: как RAG-пайплайны, векторные базы данных и развертывание LLM на самом деле работают в продакшене

28 октября 2026

Сверка актов вручную или промптом: где LLM экономит бухгалтеру часы, а где создаёт риски

12 ноября 2026

Kotlin на максималках: 13 промтов, с которыми Android-разработка идёт быстрее рутины

29 октября 2026

Гарантия на электронику: почему устройства ломаются сразу после окончания срока и как заставить продавца починить их бесплатно

11 ноября 2026

AI вместо арт-директора: как заставить LLM писать промты для Midjourney и DALL-E так, чтобы картинки перестали быть «нейросетевыми»

1 ноября 2026

Управление проектами: полный курс, который действительно нужен, чтобы понимать команды, сроки и ресурсы до того, как вы начнёте ими управлять

1 ноября 2026