0Pricing
Java Academy · Урок

Обнаружение и устранение утечек памяти

Выявляйте распространённые схемы утечек памяти (статические коллекции, обработчики и кэши) и устраняйте их.

«Обнаружение и устранение утечек памяти» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Области кучи JVM и жизненный цикл объектов
  2. Алгоритмы сборки мусора: Serial, G1, ZGC и Shenandoah
  3. Обнаружение и устранение утечек памяти
  4. Флаги настройки сборки мусора и профилирование в JVisualVM
← Назад к Java Academy