1. jmap: командная магия
Автоматический сборщик мусора — это, конечно, прекрасно. Но даже Java-приложения могут «подтекать» (OutOfMemoryError), работать медленно или неожиданно тормозить из-за неправильного использования памяти. Причины могут быть разными:
- Утечки памяти (memory leaks): объекты, которые должны были быть удалены, продолжают «жить».
- Слишком большие объёмы данных в коллекциях.
- Ошибки в логике кэширования.
- Неосвобождённые ресурсы (например, потоки, файлы).
Ваша задача — научиться быстро находить такие проблемы. Иначе вы рискуете стать не программистом, а «разработчиком багов»!
Что такое jmap?
jmap — это утилита, входящая в стандартный комплект JDK. Она позволяет получить «снимок» (heap dump) памяти работающего Java-процесса. Этот снимок можно потом открыть в других инструментах и посмотреть, какие объекты занимают память, сколько их и кто на них ссылается.
Heap dump — это как фотография вашей кучи: все объекты, которые в ней есть, их типы, связи и размеры.
Как использовать jmap
Найдите PID процесса
Для начала нужно узнать идентификатор процесса (PID), в котором работает ваше Java-приложение. Это можно сделать разными способами:
Через jps (ещё одна утилита из JDK):
jps -l
Вы увидите список Java-процессов и их PID.
Через диспетчер задач (Task Manager) или ps в Linux.
Снимите дамп памяти
jmap -dump:format=b,file=heap.bin <PID>
- format=b — бинарный формат (подходит для анализа).
- file=heap.bin — имя файла, куда будет сохранён дамп.
- <PID> — идентификатор процесса.
Пример:
jmap -dump:format=b,file=heap.bin 12345
Что делать с heap dump?
Обычно дамп анализируют в графических инструментах (например, jvisualvm или Eclipse MAT), потому что вручную в бинарном файле искать объекты — это уже высший пилотаж и немного мазохизм.
Другие возможности jmap
Просмотр статистики памяти:
jmap -heap <PID>
Показывает информацию о куче: размер, используемый GC, состояние.
Список классов:
jmap -histo <PID>
Показывает статистику по классам: сколько объектов какого типа, общий размер.
Пример вывода:
| # | Объект | Кол-во | Байты |
|---|---|---|---|
| 1 | |
1200 | 48000 |
| 2 | |
1000 | 32000 |
| 3 | |
200 | 12800 |
Это уже даёт представление: если у вас внезапно миллионы объектов какого-то типа — есть повод задуматься.
2. jvisualvm: визуальный анализатор памяти
jvisualvm — это графическая программа, входящая в JDK (посмотрите в папке bin). Она позволяет подключаться к локальным (и иногда удалённым) Java-процессам, мониторить их в реальном времени, снимать heap dump, смотреть статистику по памяти, потокам, GC, CPU и даже профилировать выполнение кода.
Если вы любите мышкой кликать и смотреть красивые графики — это ваш инструмент.
Как запустить jvisualvm
В командной строке (или через ярлык в Windows):
jvisualvm
Откроется окно, где вы увидите список всех локальных Java-процессов.
Основные функции jvisualvm
Мониторинг памяти в реальном времени
- Выберите процесс в списке слева.
- Перейдите на вкладку Monitor.
- Вы увидите графики использования heap, CPU, количество потоков и классов.
Пример:

Heap Dump (Снимок памяти)
- На панели Monitor нажмите Heap Dump.
- Через несколько секунд появится вкладка с анализом дампа.
- Вы увидите список всех классов, количество объектов, их общий размер.
Поиск «тяжёлых» объектов
- Сортируйте по размеру или количеству.
- Если видите, что какой-то тип (например, ArrayList или String) занимает слишком много памяти — это повод для расследования.
Анализ ссылок (Reference Graph)
- Кликните на класс — увидите, кто ссылается на объекты этого класса.
- Можно «докопаться» до корня: почему объект не удаляется сборщиком мусора.
Анализ потоков
- Вкладка Threads — показывает все потоки, их состояние.
- Можно выявить «зависшие» или слишком активные потоки.
Профилирование
- Вкладка Profiler — позволяет измерять, какие методы занимают больше всего времени или памяти.
- Это уже глубокий анализ, но для поиска утечек памяти достаточно первых шагов.
3. Практика: анализируем утечку памяти
Пример кода с утечкой
import java.util.ArrayList;
import java.util.List;
public class MemoryLeakDemo {
// Статическая коллекция — классика жанра!
private static final List<String> bigList = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 1_000_000; i++) {
bigList.add("Строка номер " + i);
if (i % 100_000 == 0) {
System.out.println("Добавлено: " + i);
Thread.sleep(500); // Даем время для анализа
}
}
System.out.println("Готово! Не закрывайте приложение, откройте jvisualvm.");
Thread.sleep(600_000); // 10 минут — время на анализ
}
}
Что происходит?
- Мы создаём статический список и добавляем в него миллион строк.
- После завершения добавления программа «зависает» (ждёт), чтобы вы могли подключиться к ней инструментами анализа.
Анализ через jvisualvm
- Запустите программу.
- Откройте jvisualvm и выберите процесс.
- На вкладке Monitor посмотрите график памяти.
- Если всё хорошо, память после GC должна «освобождаться».
- Если есть утечка, память только растёт.
- Сделайте Heap Dump.
- Посмотрите, какие объекты занимают больше всего памяти.
- В нашем случае — java.util.ArrayList и java.lang.String.
- Кликните на объект — посмотрите, кто на него ссылается.
- Увидите, что это статическое поле bigList.
Как исправить?
- Удаляйте ненужные элементы из коллекций, ограничивайте их рост.
- Зануляйте ссылки на тяжёлые объекты, когда они больше не нужны.
- Не держите большие коллекции в static, если они не нужны постоянно.
4. Другие инструменты: Eclipse MAT, jconsole
Eclipse Memory Analyzer (MAT)
Eclipse MAT — это бесплатный, но при этом мощный инструмент для анализа heap dump. С его помощью можно увидеть, какие объекты занимают память и какие из них удерживают другие — так называемый retained set. Это позволяет точно определить, где прячется утечка.
Инструмент умеет строить подробные отчёты по подозрительным объектам (leak suspects) и спокойно справляется даже с гигантскими дампами размером в несколько гигабайт.
Работает всё просто: вы снимаете дамп памяти с помощью jmap или jvisualvm, открываете его в MAT, нажимаете кнопку Leak Suspects Report — и получаете готовый отчёт, где уже подсвечены потенциальные проблемы.
jconsole
jconsole — это простой и удобный инструмент для наблюдения за JVM в реальном времени. Он показывает, сколько памяти используется, насколько загружен процессор, сколько потоков работает и как ведёт себя сборщик мусора.
В отличие от более продвинутых инструментов вроде VisualVM, jconsole не анализирует heap dump, зато отлично подходит для быстрой диагностики — когда нужно одним взглядом понять, что сейчас происходит внутри приложения.
5. Типичные ошибки при анализе памяти
Ошибка №1: Снимаете дамп не того процесса. Часто на машине крутится много Java-приложений, и можно перепутать PID. Проверяйте через jps и убедитесь, что анализируете именно вашу программу.
Ошибка №2: Ожидаете увидеть «утечку» там, где её нет. GC может не сразу удалять объекты — иногда память «отпускается» только после Full GC. Не паникуйте, если после одной итерации память не освободилась — посмотрите на тренд.
Ошибка №3: Не учитываете влияние статических/кэшированных объектов. Многие утечки связаны с тем, что объекты хранятся в static-полях или глобальных коллекциях. Проверяйте, кто ссылается на «тяжёлые» объекты — это часто static.
Ошибка №4: Не используете профилирование в динамике. Heap dump — это хорошо, но иногда важно смотреть на рост памяти во времени (графики в jvisualvm). Если память стабильно растёт — есть повод для расследования.
Ошибка №5: Не удаляете слушателей/обработчики событий. Если вы подписались на событие, но не отписались — объект будет «жить» в памяти, даже если вы его больше не используете.
Совет: Не бойтесь экспериментировать с инструментами! Снимайте дампы, смотрите графики, кликайте по объектам — только так вы научитесь «чувствовать» память своей программы и быстро находить проблемы.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ