Сборщик мусора начинает с корневых объектов (root objects), таких как глобальные переменные, локальные переменные текущих функций и регистры. Все объекты, достижимые из корневых объектов, маркируются как используемые. Рекурсивно проходя по всем ссылкам, сборщик помечает все достижимые объекты.
Roots -> Object A -> Object B
-> Object C
(Объекты A, B и C помечены как используемые)
В процессе маркировки сборщик мусора строит граф объектов, где узлы представляют объекты, а ребра — ссылки между ними. Объекты, которые не помечены в процессе обхода, считаются недостижимыми.
После определения недостижимых объектов, сборщик мусора приступает к освобождению памяти, занятой этими объектами.
Память, занимаемая недостижимыми объектами, освобождается, что делает её доступной для повторного использования. Если используется сборщик мусора с финализацией, сначала вызываются финализаторы объектов, а затем память освобождается.Компактирование памяти. Некоторые алгоритмы сборки мусора выполняют также компактирование памяти для уменьшения фрагментации.
Object D (недостижимый) -> память освобождена
Достижимые объекты могут быть перемещены для создания непрерывных блоков свободной памяти. Перемещение объектов требует обновления всех ссылок на перемещенные объекты. Обновление ссылок. Если объекты перемещаются в процессе компактирования, все ссылки на эти объекты должны быть обновлены.
[Object A][Object B][free space][Object C][free space] -> [Object A][Object B][Object C][free space]
Все указатели, которые указывают на перемещенные объекты, должны быть изменены так, чтобы указывать на новые адреса. Финализация объектов. Некоторые языки поддерживают финализаторы (аналог деструкторов), которые вызываются до того, как объект будет окончательно удален.
Если объект имеет финализатор, он вызывается перед освобождением памяти объекта. Это позволяет объекту выполнить завершающие действия, такие как освобождение ресурсов или выполнение каких-либо специфичных для приложения задач.
#include <iostream>
class MyClass {
public:
~MyClass() {
// Завершающие действия
std::cout << "Finalizing MyClass" << std::endl;
}
};
int main() {
MyClass obj;
// Другие операции с obj
return 0;
}
Объекты помечаются как используемые, а затем недостижимые объекты удаляются. Простая реализация, но может приводить к фрагментации памяти. Избегает фрагментации, но требует удвоения памяти.
Память делится на поколения: молодые объекты, старые объекты и объекты в промежуточной стадии. Молодые объекты чаще всего удаляются быстрее, что позволяет оптимизировать сборку мусора.
Ставь 👍 и забирай 📚 Базу знаний