ПрограммированиеJava разработчик

Как работает механизм автоматического управления памятью в Java (Garbage Collector)?

Проходите собеседования с ИИ помощником Hintsage

Ответ

В Java управление памятью осуществляется за счёт автоматической сборки мусора (Garbage Collector, GC). JVM самостоятельно отслеживает объекты в памяти: если на объект больше нет ссылок, он становится недостижимым и может быть удалён.

GC состоит из разных фаз, таких как Mark, Sweep и иногда Compact. В фазе Mark объекты, до которых можно дотянуться из корней (GC roots), помечаются как живые. После этого начинается Sweep: неиспользуемые объекты удаляются. Иногда выполняется Compact — дефрагментация памяти.

Есть разные типы GC: Serial, Parallel, CMS, G1. Их стоит выбирать в зависимости от типа нагрузки на приложение.

Пример кода — ситуация утечки памяти:
List<byte[]> dataList = new ArrayList<>(); while(true) { dataList.add(new byte[1024*1024]); // Объекты остаются достижимыми }

В этом примере объекты никогда не станут недостижимыми, GC их не удалит, и произойдёт OutOfMemoryError.

Вопрос с подвохом

Если у объекта больше нет ссылок, когда гарантируется вызов его финализатора (finalize())?

Ответ: Вызов метода finalize() не гарантируется вовсе! Он может быть вызван ни разу или с задержкой. Нельзя полагаться на finalize() для освобождения ресурсов.

@Override protected void finalize() throws Throwable { // Может не отработать! }

Примеры реальных ошибок из-за незнания тонкостей темы


История

В крупной e-commerce системе разработчики надеялись автоматизировать очистку временных файлов с помощью метода finalize(), но из-за редкого вызова этого метода кэш переполнился временными файлами, что привело к нехватке диска и простоям.


История

В high-load REST API случайно был сохранён внутренний кеш ссылок на большие объекты, что препятствовало освобождению памяти. После падения приложения с OutOfMemoryError анализ показал ошибку в методе кэширования.


История

Финализаторы использовались для освобождения сетевых соединений, считая это "надежным способом". Это приводило к тому, что соединения висели в системе неопределённо долго, вызывая блокировки и истощение пула соединений.