Ответ
Утечка памяти в Java возникает, когда объекты больше не нужны приложению, но остаются достижимыми для сборщика мусора (GC), не allowing их удалить.
Распространённые причины и примеры:
-
Статические поля, особенно коллекции: Объекты, добавленные в статическую коллекцию, живут всё время жизни класса.
public class MemoryLeak { private static final List<byte[]> LEAK = new ArrayList<>(); public void causeLeak() { LEAK.add(new byte[1024 * 1024]); // 1MB добавляется и никогда не удаляется } } -
Незакрытые ресурсы (
Closeable): Потоки, соединения с БД, сокеты.try { FileInputStream fis = new FileInputStream("largefile.zip"); // Чтение данных... // fis.close(); // УТЕЧКА: поток и связанный с ним native-буфер не освобождаются } catch (IOException e) { ... } // Всегда используйте try-with-resources! -
Неправильные реализации
equals()иhashCode(): Объекты, помещённые вHashSetили как ключи вHashMap, могут стать "потерянными", если их хэш-код изменяется, делая их недостижимыми для стандартного поиска, но они остаются в коллекции. -
Слушатели событий (Listeners) и callback-и: Если не отписаться, внешний объект удерживается в памяти.
Инструменты для диагностики: VisualVM, Eclipse Memory Analyzer (MAT), Java Flight Recorder (JFR). Они помогают анализировать heap dump и находить цепочки ссылок, удерживающие объекты.