Как называется проблема, когда сборщик мусора не удаляет объекты из-за живых ссылок
Что проверяют
Знаете ли вы термин и, что важнее, типичные источники таких ссылок в реальном коде.
Как отвечать
Это утечка памяти. Формально сборщик работает правильно: он удаляет только недостижимые объекты, а здесь ссылка остаётся, хотя объект уже не нужен. Отсюда парадокс: язык с автоматическим управлением памятью, а память течёт.
Типичные источники стоит перечислить, это и есть содержательная часть ответа:
- статические коллекции: кеш или список в статическом поле, куда кладут и не убирают. Живёт всё время работы приложения;
ThreadLocalв пуле потоков: поток не умирает, значит значение остаётся навсегда. Классика для веб-приложений;- неотписанные слушатели и колбэки: объект подписался на события и не отписался, издатель держит ссылку;
- незакрытые ресурсы: соединения, потоки ввода-вывода, сессии;
- ключи в
HashMapс изменяемым состоянием: запись становится недостижимой по ключу, но остаётся в памяти; - утечка загрузчика классов в серверах приложений при переразвёртывании: один живой объект тянет за собой весь загрузчик со всеми классами.
Как ищут: рост занятой памяти после полной сборки, снятие дампа кучи (jcmd GC.heap_dump), анализ в Eclipse MAT через дерево доминаторов и отчёт о подозрительных объектах. Ответ на вопрос «кто держит ссылку» виден там прямо.
Как чинят: убирать ссылки явно, ограничивать размер кеша, использовать слабые ссылки там, где кеш не должен удерживать объект, чистить ThreadLocal в конце обработки запроса.
Где спотыкаются
Считают, что в Java утечек не бывает.
Ищут причину в самом сборщике, а не в своих ссылках.
Лечат симптом увеличением кучи, отодвигая падение вместо устранения причины.