Основные проблемы с памятью Java
В этом разделе объясняются часто возникающие проблемы с памятью, такие как утечки памяти, высокий уровень использования памяти, проблемы с загрузчиком классов и конфигурация сборщика мусора.
Утечки памяти
Наиболее распространенная проблема утечки памяти - это растущие утечки памяти или постоянный рост утечек объектов. Эти утечки можно легко отследить с помощью дампов трендов или гистограмм.
Для сравнения, об утечках отдельных объектов говорят меньше. Пока памяти достаточно, одиночные утечки памяти редко представляют серьезную проблему. Однако время от времени утечки отдельных объектов занимают значительный объем памяти и создают проблемы. Хорошая новость заключается в том, что отдельные большие утечки можно легко обнаружить с помощью инструментов анализа кучи.
Ниже приведены некоторые из причин утечки памяти:
Локальные переменные потока
- Переменные ThreadLocal используются для привязки переменной или состояния к потоку. У каждого потока есть собственный экземпляр переменной. Хотя переменные ThreadLocal могут быть полезны, они также могут быть опасными. Они используются для отслеживания состояния, например идентификатора текущей транзакции, но иногда содержат дополнительную информацию. На переменную ThreadLocal ссылается ее поток, и ее жизненный цикл привязан к ней. На большинстве серверов приложений потоки повторно используются через пулы потоков и никогда не собираются сборщиком мусора. Если код приложения не очищает переменную ThreadLocal тщательно, это приводит к неприятной утечке памяти. Такие утечки можно легко обнаружить с помощью дампа кучи, просмотрев ThreadLocalMap и следуя ссылкам. На приведенном выше экране heapdump указывает, что более 4К объектов, размер которых составляет около 10 МБ, удерживаются переменными ThreadLocal. Название потока показывает, какая часть приложения ответственна за утечку.
Изменяемые статические поля и коллекции
- Наиболее частая причина утечки памяти - неправильное использование статики. Статическая переменная хранится в ее классе, а затем в загрузчике классов. Хотя класс можно собирать мусором, это редко происходит в течение жизненного цикла приложения. Часто статика используется для хранения информации кеша или обмена состоянием между потоками. Если этого не делать прилежно, легко получить утечку памяти. По этой причине следует избегать статических изменяемых коллекций любой ценой. Хорошее архитектурное правило - вообще не использовать изменяемые статические объекты и довольствоваться лучшими альтернативами.