JavaRush /Курсы /Java Collections /Сборка мусора

Сборка мусора

Java Collections
4 уровень , 3 лекция
Открыта

— Привет! Снова решила устроить тебе небольшую лекцию про сборку мусора.

Как ты уже знаешь, Java-машина сама отслеживает ситуации, когда объект становится ненужным и удаляет его.

— Ага. Вы с Ришей раньше мне рассказывали об этом, нюансов я не помню.

— Ок. Тогда повторим.

Сборка мусора - 1

Как только объект создается, Java выделяет ему память. А за востребованностью объекта следит с помощью переменных-ссылок. Объект может быть удален при «сборке мусора» — процедуре очистки памяти, если не остается переменных, которые ссылаются на этот объект.

— А расскажи немного о сборщике мусора, что это такое и как он работает.

— Ок. Раньше сборка мусора происходила в главном потоке/нити. Раз в 5 минут, или чаще. Если наступал случай, когда не хватало свободной памяти, Java-машина приостанавливала работу всех нитей и удаляла неиспользуемые объекты.

Но сейчас от этого подхода отказались. Сборщик Мусора нового поколения работает незаметно и в отдельном потоке. Такую сборку мусора принято называть параллельной.

— Ясно. А как именно определяется – нужно удалять объект или нет.

— Просто считать количество ссылок на объект не очень эффективно – ведь могут быть объекты, которые ссылаются друг на друга, но больше на них не ссылается никто.

Поэтому в Java применяется другой подход. Java делит объекты на достижимые и недостижимые. Объект считается достижимым (живым), если на него ссылается другой достижимый (живой) объект. Достижимость считается от нитей. Работающие нити всегда считаются достижимыми (живыми), даже если на них никто не ссылается.

— Ок. С этим вроде ясно.

А как происходит сама уборка мусора – удаление ненужных объектов?

— Тут все просто. В Java память условно разделена на две части, и когда приходит время сборки мусора, все живые (достижимые) объекты копируются в другую часть памяти, а старая память вся освобождается.

— Интересный подход. И не надо считать ссылки – скопировал все достижимые объекты, а все остальные – мусор.

— Там все немного сложнее. Программисты Java выяснили, что объекты обычно делятся на две категории – долгоживущие (которые существуют все время работы программы) и маложивущие (нужны в методах и для выполнения «локальных» операций).

Хранить долгоживущие отдельно от маложивущих гораздо эффективнее. Для этого надо было придумать механизм определения долгожительства объекта.

Поэтому они разделили всю память на «поколения». Есть объекты первого поколения, есть объекты второго поколения и т.д. Каждый раз после очистки памяти счетчик поколений увеличивается на 1. Если какие-то объекты существуют много поколений, то их записывали в долгожители.

Сборщик Мусора очень — сложная и эффективная составляющая Java. Многие его части работают эвристически – на основе алгоритмов-догадок. Поэтому он часто «не слушается» пользователя.

— В смысле?

— У Java есть объект GC (Garbage Collector – Сборщик Мусора), который можно вызвать с помощью метода System.gc().

Также можно принудительно инициировать вызов finalize-методов удаляемых объектов, посредством System.runFinalization(). Но дело в том, что по документации Java, это не гарантирует ни начало сборки мусора, ни вызов методов finalize(). Garbage Collector сам решает, что и когда ему вызывать.

— Ничего себе! Буду знать.

— Но и это еще не все. Как ты знаешь, в Java одни объекты ссылаются на другие, и именно с помощью этой сети ссылок определяется – стоит удалять объект или нет.

Так вот, в Java есть специальные ссылки, которые позволяют влиять на этот процесс. Для них есть специальные классы-обертки. Вот они:

SoftReference – мягкая ссылка.

WeakReference – слабая ссылка.

PhantomReference – призрачная ссылка.

— М-да. Чем-то напоминает внутренние классы, вложенные классы, внутренние анонимные классы, локальные классы. Названия разные, но по ним совсем не понятно за что они отвечают.

— Вот ты, Амиго, и стал программистом. Теперь ты возмущаешься по поводу названий классов – дескать, недостаточно информативны, и нельзя по одному названию(!) определить, что этот класс делает, как и зачем.

— Ого. А я и сам не заметил. Но это же так очевидно.

Ладно. Соловья баснями не кормят. Давай я тебе расскажу про SoftReference – мягкие ссылки.

Эти ссылки были специально придуманы для кэширования, хотя их можно использовать и для других целей – все на усмотрение программиста.

Пример такой ссылки:

Пример
//создание объекта Cat
Cat cat = new Cat();

//создание мягкой ссылки на объект Cat
SoftReference<Cat> catRef = new SoftReference<Cat>(cat);

//теперь на объект ссылается только мягкая ссылка catRef.
cat = null; 

//теперь на объект ссылается еще и обычная переменная cat
cat = catRef.get();

//очищаем мягкую ссылку
catRef.clear();

Если на объект существуют только мягкие ссылки, то он продолжает жить и называется «мягкодостижимым».

Но! Объект, на который ссылаются только мягкие ссылки, может быть удален сборщиком мусора, если программе не хватает памяти. Если программе вдруг не хватает памяти, прежде чем выкинуть OutOfMemoryException, сборщик мусора удалит все объекты, на которые ссылаются мягкие ссылки и попробует выделить программе память еще раз.

Предположим, что программа-клиент часто запрашивает у программы-сервера различные данные. Тогда программа сервер может некоторые из них кэшировать, воспользовавшись для этого SoftReference. Если объекты, удерживаемые от смерти мягкими ссылками, будет занимать большую часть памяти, то сборщик мусора просто их поудаляет и все. Красота!

— Ага. Мне самому понравилось.

— Ну и маленькое дополнение: у класса SoftReference есть два метода. Метод get() возвращает объект, на который ссылается SoftReference. Если объект был удален сборщиком мусора, внезапно(!) метод get() начнет отдавать null.

Так же пользователь может сам очистить SoftReference, вызвав метод clear(). При этом слабая ссылка внутри объекта SoftReference будет уничтожена.

На этом пока все.

— Спасибо за интересный рассказ, Элли. Действительно было очень интересно.

Комментарии (49)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Natalya Уровень 46
28 апреля 2025
Робот-пылесос назвала GC
{Java_Shark} Уровень 36
11 февраля 2025
++
SomeBody098 Уровень 51
7 октября 2024
Не верь, не бойся, не проси — Работай, мусор выноси.
Denis Odesskiy Уровень 47
29 октября 2024
А если мусор вдруг остался, На С++ переходи. Там память будешь выделять, И не бояться, удалять, Пока не совершишь ошибку, И не получишь прямо в глаз.
Vadym Уровень 38
16 мая 2023
https://youtu.be/UAq7qwNPIog рекомендую посмотреть
Василий Чи Уровень 51
16 января 2023
Теперь мой хлам на балконе будет называться вещами с мягкими ссылками)
Станислав Future Уровень 39
22 августа 2022
В общем сборщик мусора работает мудрено, нюансов я не запомню. Хотите управлять памятью понятно и эффективно - велком в С++, будете ручками там выделять и удалять память на каждый объект.
Anonymous #3113984 Уровень 51
23 августа 2022
Об этих классах-обертках важно только знать, ибо никогда не применятся руками.
Denis Odesskiy Уровень 47
29 октября 2024
Говорят, если в C++ неправильно управлять памятью, то к вам домой может прийти сосед-психопат, который делал ревью вашего кода, и выстрелить в голову ногу.🤯
LuneFox Уровень 41 Expert
18 января 2022
То есть, объект, на который ссылается только мягкая ссылка, "нужен, но не очень"? -- Эй программист, тебе ещё нужен этот объект? -- Ну... не знаю... наверное да... а хотя погоди, не... а вдруг понадобится? Маловеоятно, конечно, но всякое может быть, ну в общем, если место есть, поставь куда нибудь, ну а если нет, ладно, выкидывай.
Роман Кончалов Уровень 28 Expert
31 марта 2022
Да, кеширование так и работает. Сейчас данные не нужны, но потом могут пригодиться, хотя в крайнем случае их можно и заново загрузить из другого места, если кончилось место в оперативке и данные были удалены. Поэтому многие ноют, что Chrome жрёт слишком много памяти, хотя он жрёт ровно столько сколько свободно (с некоторым ограничением: 60-80% от свободной памяти). И когда мы открываем много вкладок они естественно кешируются сначала в оперативную память, а потом на жёсткий диск. И чем больше у нас оперативная память, тем больше хром постарается оставить в ней, чтобы не обращаться к медленному жёсткому диску или изнашиваемому SSD.
Denis Odesskiy Уровень 47
29 октября 2024
@-- Эй программист, тебе ещё нужен этот объект? - Да нет ну может быть наверное!
Игорь Уровень 41
26 июля 2021
Динамический массив на си++ int *arr = new int[size]; delete []arr; Выделяем байтитки для динамического массива в си int *arr = malloc(sizeof(int) * size); free(arr);
Олег Д Уровень 40
15 июля 2021
мягкодостижимый объект)) плюсуй, если бывшую свою вспомнил))
Denis Уровень 40
9 октября 2021
😆
Андрій Мовчан Уровень 1
30 октября 2021
Годно😂
LuneFox Уровень 41 Expert
18 января 2022
Жёны декабристов тоже считали своих мужей мягкодостижимыми, потому смогли достигнуть их через ссылку?