Коротко о самом главном в сборке мусора.
⚠️ Важно: это только концептуальная иллюстрация. В реальных средах исполнения JVM возможно других все сложнее!
💡 Терминология:
🔹 Stop The World
В управляемых языках это "механизм" остановки ваших потоков, для того, чтобы GC мог почистить память от ненужных объектов.
🔹 GC_POLL()
Фунция (на самом деле кусочек ассемблера), которая встраивается в ваш код и останавливает его исполнение по требованию GC.
🔹 Safe points
Места в вашем коде, куда может встроиться функция GC_POLL()
Где Safe points и где может встроиться GC_POLL():
На входе в функцию
В конце горячих циклов (много итераций)
На выходе из функции
После вашего new (аллокации памяти) - если тип ссылочный
После вызовов функций
На определённых точках в коде с долгими вычислениями
По желанию производителей компилятора...
⚠️ Safe points расставляются компилятором, программист напрямую на это не влияет.
⚙️ Примерный порядок действий:
Компилятор вставляет в Вашу программу функцию и флаг, они доступны из любой точки программы
//Флаг остановки мира volatile bool gc_stop_the_world = false; inline void GC_POLL() { if (gc_stop_the_world) { //Функция прерывающая выполнение //текущего потока кода, ваш код замирает SuspendCurrentThread(); } }
Расставляет функцию GC_POLL() по вашему коду в безопасных точках (Safe Points)
Ваша функция:
void Foo(int count) { GC_POLL(); //Вы этого не писали //...Какой-то ваш код for(var i = 0; i < count; ++i) { //...Какой-то ваш код GC_POLL() //Вы этого не писали } GC_POLL(); //Вы этого не писали }
⚠️ Важно: компилятор вставляет минимальный ассемблерный код, а не прям call функции GC_POLL(), вызов GC_POLL() - представлен для урощения.
При старте вашей программы запускается поток Вашей программы и отдельный поток/и GC, например такая функция:
//Функция самого GC (Сборщик мусора, он же Garbage Collector) //Она работает параллельно с вашей программой void GC_WORK() { while(true) { //Проверяем надо ли чистить память if(NeedToClearMemory()) { //Выставляем флаг "остановки мира" gc_stop_the_world = true; //Ждем когда все нужные потоки остановятся WaitStopTheWorld(); //Очистка памяти ClearMemory(); //Сбрасываем флаг "остановки мира" gc_stop_the_world = false; //Запускаем потоки в работу RunTheWorld(); } else { Sleep(1); //Например можно засыпать на 1 мс } } }
Когда GC решает что памяти мало, он:
Поднимает флаг gc_stop_the_world.
Потоки самостоятельно доходят до GC_POLL() и приостанавливаются.
GC ждет остановку всех нужных потоков
Чистит память
Cбрасывает флаг gc_stop_the_world.
Возобновляет работу Ваших потоков.
⚠️ Ваш код сам может вызвать работу GC, если вы вызвали аллокацию (создали новый управляемый объект), а свободной памяти у менеджера памяти нет:
var x = new byte[1000]; // Этот код может сам заставить GC выполнить работу, // потому-что на самом деле вызывается код аллокатора памяти // и просит минимум 1000 байт
⚠️ Некоторые потоки могут быть неуправляемыми тогда GC пропускает их при проверке.
