Мне НЕ нужно разбираться с управлением памятью в Java, так как за меня всё делает GC
Garbage Collector (GC) действительно очищает неиспользуемые объекты, которые больше не имеют активных ссылок. Благодаря этому в Java не нужно вручную освобождать память, как в C++.
Несколько предпосылок к исходному тезису:
🔹 В других языках, где ручное управление памятью (C, C++), утечки очевидны — если забыл free(), память навсегда потеряна.
🔹 В Java GC работает автоматически, поэтому кажется, что он решает все проблемы сам.
🔹 "Ну раз GC есть, значит, про память можно не думать!" — типичная ошибка.
GC удаляет только те объекты, которые больше не имеют активных ссылок. Если же объект остаётся доступным, но фактически не используется, он будет занимать память до завершения работы приложения.
🔽 Несколько случаев утечек памяти
1️⃣ Статические коллекции (заполняем, но не чистим)
Если создать static List и постоянно добавлять в него объекты, они никогда не будут удалены GC, потому что статические поля живут весь срок жизни приложения.
public class MemoryLeak {
private static final List<byte[]> cache = new ArrayList<>();
public static void main(String[] args) {
while (true) {
cache.add(new byte[10 * 1024 * 1024]);
System.out.println("Добавили 10MB в кеш. Используемая память: " +
(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024) + "MB");
}
}
}Через пару минут — OutOfMemoryError
2️⃣ Потоковые переменные (ThreadLocal)
Объекты, хранящиеся в ThreadLocal, привязываются к потоку, а в пуле потоков они могут жить дольше, чем нужно.
public class ThreadLocalLeak {
private static final ThreadLocal<byte[]> threadLocalData = new ThreadLocal<>();
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executor.execute(() -> {
threadLocalData.set(new byte[10 * 1024 * 1024]); // 10MB на поток
System.out.println("Память занята потоком!");
});
}
executor.shutdown();
}
}Поток завершится, а память останется занята, потому что ThreadLocal не очищается автоматически.
3️⃣ Внутренние классы и "утекшие" ссылки
Если анонимный класс или лямбда-ссылка ссылается на внешний объект, она может мешать GC очистить его.
public class InnerClassLeak {
private String data = "Очень важные данные";
public void createAnonymousClass() {
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("Используем: " + data);
}
};
new Thread(task).start();
}
}task ссылается на data, даже если InnerClassLeak больше не используется → GC не очистит объект.
👎 Миф разрушен. GC не всемогущий и даже с ним придётся изучать, как работать с памятью в Java.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava