Ответ
Утечка памяти (memory leak) в Java — это ситуация, когда объекты больше не используются приложением, но не могут быть собраны сборщиком мусора (GC) из-за сохраненных ссылок на них.
Основные причины:
- Статические поля (живут пока жив класс)
- Неотписанные слушатели (например,
OnClickListener) - Незакрытые ресурсы (
Cursor,InputStream) - Внутренние классы, хранящие ссылку на внешний (
Handlerв Activity)
Пример утечки:
public class LeakyActivity extends Activity {
private static Context sContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sContext = this; // Утечка! Activity не сможет быть собрана GC
}
}
Как избежать:
- Используйте WeakReference для ссылок на контекст
- Всегда отписывайтесь от событий в
onDestroy() - Используйте
try-with-resourcesдля AutoCloseable объектов - Для Handler используйте статический внутренний класс + WeakReference
Ответ 18+ 🔞
Давай разберём эту хрень про утечки памяти в Java, а то народ потом охуевает, почему приложение тормозит и вылетает. Представь, что твоя программа — это комната, а объекты — это хлам, который ты туда накидал. Сборщик мусора (GC) — это твоя бабка, которая приходит и выкидывает всё, чем ты не пользуешься. Утечка памяти — это когда ты, ёпта, прибил этот хлам гвоздями к стене, и бабка его выкинуть не может, хотя он тебе уже нахуй не нужен. Комната забивается, и жить там невозможно.
Основные причины, из-за которых эта пиздопроебибна случается:
- Статические поля. Это как повесить фотографию своей бывшей на самом видном месте и забыть её там. Она будет висеть, пока дом стоит (то есть пока жив класс). Объект, на который ссылается статика, никогда не умрёт.
- Неотписанные слушатели (типа
OnClickListener). Ты подписался на рассылку, а отписаться забыл. Тебе каждый день приходит спам, а ты удивляешься, почему почтовый ящик трещит по швам. Активность хочет умереть, а какой-нибудь менеджер держит на неё ссылку через этот слушатель. - Незакрытые ресурсы (
Cursor,InputStream). Это как оставить кран открытым в ванной и уйти в запой на неделю. Вода (память) льётся, пока всё не затопит.Терпения ноль ебатьна таких разработчиков. - Внутренние классы, хранящие ссылку на внешний. Классика —
Handlerв Activity. Внутренний класс знает про своего родителя и держит его за руку, даже когда того уже пора хоронить. Activity не может собраться, и у тебя волнение ебать, откуда утечка.
Вот тебе наглядный пример, как самому себе ногу прострелить:
public class LeakyActivity extends Activity {
private static Context sContext; // Статическое поле — наш главный враг
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sContext = this; // Вот она, утечка! Activity теперь пригвождена к жизни навечно.
}
}
Что происходит? Ты присвоил статическому полю sContext ссылку на текущую Activity (this). Активность завершилась, но статическая переменная, которая живёт вечно, продолжает на неё ссылаться. GC смотрит на это и говорит: «Ну, раз на неё ещё кто-то ссылается, значит, нужна». И не трогает. Активность не уничтожается, память не освобождается. Повтори это 10 раз — и приложение накрылось медным тазом.
Как не наступать на эти грабли:
- Используй
WeakReferenceдля ссылок на контекст. Это как дать бабке записку с адресом хлама, а не сам гвоздь. Если объект станет не нужен, GC его спокойно выкинет, а твоя слабая ссылка просто обнулится. - Всегда отписывайся от событий в
onDestroy(). Закрывай за собой дверь. Ушёл из активности — отпишись от всех слушателей, наблюдателей и прочей хуйни, которая может держать тебя в памяти. - Используй
try-with-resourcesдляAutoCloseableобъектов. Это магия, которая сама закроет твойInputStreamилиCursor, даже если посередине операции вылетит исключение. Красота, а не жизнь. - Для
Handlerиспользуй статический внутренний класс +WeakReference. Сделай хендлер статическим, чтобы он не знал про внешний класс, а если нужно достучаться до активности — передавай её черезWeakReference. Тогда, когда активность умрёт, хендлер не будет мешать GC её прибрать.
Короче, чувак, суть в том, чтобы не создавать цепочек, которые мешают мусорщику работать. Дай ему возможность выкинуть то, что тебе уже не нужно, и твоё приложение не будет жрать память, как не в себя. Иначе пользователи тебе такого наговорят, что мало не покажется.