[Из песочницы] OutOfMemoryError. Боремся с утечками памяти в Android

В данной заметке мы рассмотрим несколько примеров утечек памяти в Android приложении. Также мы рассмотрим исправления этих утечек. Я хочу показать, что с утечками памяти можно и нужно бороться. Я не буду рассказывать про инструменты для анализа памяти, только лишь приведу ссылки на самые важные из них.
Для привлечения внимания к новому функционалу было принято решение воспользоваться анимацией. Необходимо было показать на короткий период View с подсказкой. Пример можно увидеть на изображении ниже:

Гифка с примером
7f80edbc99ed4def8419cad2782804c2.gif


Позже обнаружилась утечка Activity.

980c9158dc344ecc9377f0328a01e13c.png

Проблема заключалась в том, что анимация fadeOut использовала слушателя от анимации fadeIn, что приводило к бесконечному запуску анимации fadeOut.

f58cf3b78a714862acef31b40b791fc7.png

Исправить это было достаточно легко.

84f7afeafc7d442c860e224e29c1f8bb.png

Анимации часто являются причинами утечек. Этого очень легко достигнуть забыв остановить бесконечную анимацию или запустив анимацию на неоправданно длительное время.


Бывает утечки памяти находятся и в самой платформе. Однажды я получил такой отчет:

b6f6c641c88247b7a523fee0d0ed595e.png

Чтобы воспроизвести утечку достаточно создать Dialog с EditText внутри и что-нибудь в нем напечатать.

Гифка с примером
37af1aabfb9e4585b7dff0012730c109.gif


Как оказалось, это известный баг и он уже исправлен. Там же можно найти хак, для исправления этой утечки:

b07bb66f7fb942028e83baaa5158e07d.png


В одном из отчетов я получил утечку с не публичным, неизвестным мне ранее классом. Оказалось, что это приватный класс от одного популярного производителя.

753a6bdcd133426ba99519a4a72c7973.png

На этот раз мне опять повезло и я нашел готовое решение в сети (1, 2).

417da4bb674545919392fb1aeec7e634.png


023e0c359b6149a6ae53354470fee625.png

В результате количество OutOfMemoryError уменьшилось почти в 7 раз. Так же уменьшилось количество RuntimeException, InflateException: часть из них — это пойманные и обернутые OutOfMemoryError. Одним из ограничивающих факторов в исправлении такого рода ошибок является то, что я не могу делать обновления, которые не содержат внешних изменений (для пользователей выглядит как «Пустое обновление») В таких случаях приходится ждать реализации нового функционала для проверки результатов.


  • Документируйте не тривиальные/не очевидные моменты в коде, которые исправляют утечки памяти. Часто они выглядят подозрительно.
  • Не ошибается тот, кто ничего не делает. Иногда приходится фиксить утечки памяти в чужом коде.
  • Нужно знать свой инструментарий (hprof-conv, VisualVM, OQL, leakcanary)
  • Обязательно делайте измерения и следите за ними (crash-report tools).
  • Не допускайте увеличения количества ошибок.


© Habrahabr.ru