Обнаружение и устранение утечек памяти
Выявляйте распространённые схемы утечек памяти (статические коллекции, обработчики и кэши) и устраняйте их.
«Обнаружение и устранение утечек памяти» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Что такое утечка памяти в Java?
Утечка памяти в Java возникает, когда ненужные объекты остаются сильно достижимыми, не позволяя сборщику мусора освободить их. Куча растёт, пока не будет выброшено исключение OutOfMemoryError.
Накопление в статической коллекции
Статическое поле, содержащее растущую коллекцию, — классический пример утечки. Добавленные, но никогда не удаляемые объекты остаются живыми в течение всего времени жизни приложения.
public class Cache {
// LEAK: static list grows forever if items are never removed
private static final List<Object> items = new ArrayList<>();
public static void add(Object o) { items.add(o); }
// Fix: add a remove() method or use a bounded cache
}Незарегистрированные обработчики событий
Регистрация обработчика без последующего удаления сохраняет живыми и сам обработчик, и все объекты, на которые он ссылается. Всегда удаляйте обработчики, когда они больше не нужны.
// Leak:
sensor.addListener(new DataLogger());
// Fix:
DataLogger logger = new DataLogger();
sensor.addListener(logger);
// ... when done:
sensor.removeListener(logger);Неочищенные переменные ThreadLocal
В пулах потоков значения ThreadLocal сохраняются между задачами, поскольку потоки используются повторно. Если их не очищать, данные одной задачи попадут в последующие задачи, выполняемые в том же потоке.
private static final ThreadLocal<MyContext> CTX = new ThreadLocal<>();
// Always clean up after each task:
try {
CTX.set(new MyContext(requestId));
doWork();
} finally {
CTX.remove(); // prevents leak in pooled threads
}Утечки загрузчиков классов в приложениях с горячим развертыванием
В контейнерах сервлетов каждое развертывание использует новый загрузчик классов. Если какой-либо класс хранит статическую ссылку на класс из старого загрузчика, весь старый загрузчик и все его классы не могут быть собраны сборщиком мусора.
Обнаружение утечек с помощью дампов кучи
Создайте дамп кучи с помощью jmap -dump:format=b,file=heap.hprof <pid>, затем откройте его в Eclipse MAT или VisualVM, чтобы найти крупнейшие удерживаемые объекты и их корни GC.
// Take a heap dump:
jmap -dump:live,format=b,file=heap.hprof $(jps | grep MyApp | cut -d" " -f1)
// Or trigger on OOM:
// -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heap.hprofАнализатор памяти Eclipse (MAT)
Отчёт MAT «Подозреваемые на утечки» автоматически выявляет объекты с большим объёмом удерживаемой кучи и показывает путь от корней GC. Начните с представления «Дерево доминирования», чтобы найти наиболее проблемные объекты.
Использование WeakReference для предотвращения утечек
Оберните кэшируемые объекты или объекты-слушатели в WeakReference. GC может освободить их при нехватке памяти. Всегда проверяйте результат get() на null.
Map<String, WeakReference<Image>> imageCache = new HashMap<>();
imageCache.put("logo", new WeakReference<>(loadImage("logo.png")));
Image logo = imageCache.get("logo") != null ? imageCache.get("logo").get() : null;
if (logo == null) logo = reload("logo.png"); // re-load if GCedОграниченные кэши с LinkedHashMap LRU
Переопределите removeEldestEntry в LinkedHashMap, чтобы ограничить размер кэша и автоматически удалять давно не использовавшуюся запись.
Map<String, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
protected boolean removeEldestEntry(Map.Entry<String, String> e) {
return size() > 100; // evict when over 100 entries
}
};Профилирование распределений с помощью Java Flight Recorder
JFR (Java Flight Recorder) собирает профили распределения памяти с минимальными накладными расходами. Включите его с помощью -XX:StartFlightRecording и проанализируйте данные в JDK Mission Control.
// Start a 60-second JFR recording:
java -XX:StartFlightRecording=duration=60s,filename=rec.jfr MyApp
// Or via jcmd:
jcmd <pid> JFR.start duration=60s filename=rec.jfrИсправление утечек: контрольный список
Проверьте статические коллекции, незарегистрированные слушатели, ThreadLocals в пулах, утечки соединений и потоков (используйте try-with-resources), ссылки внутренних классов на внешние объекты и кэши без удаления записей.
Быстрая проверка
Какой флаг JVM автоматически создаёт дамп кучи при возникновении OutOfMemoryError?
Итоги
Распространённые источники утечек в Java: статические коллекции, незарегистрированные слушатели, ThreadLocals в пулах и кэши без ограничения размера. Обнаруживайте утечки с помощью дампов кучи и MAT. Устраняйте их с помощью WeakReferences, ограниченных структур и обязательного удаления ссылок после завершения работы.
Часто задаваемые вопросы
Урок «Обнаружение и устранение утечек памяти» бесплатный?
Да — полный текст урока «Обнаружение и устранение утечек памяти» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Обнаружение и устранение утечек памяти»?
Выявляйте распространённые схемы утечек памяти (статические коллекции, обработчики и кэши) и устраняйте их. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Обнаружение и устранение утечек памяти»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Области кучи JVM и жизненный цикл объектов
- Алгоритмы сборки мусора: Serial, G1, ZGC и Shenandoah
- Обнаружение и устранение утечек памяти
- Флаги настройки сборки мусора и профилирование в JVisualVM