Многие языки, такие как Java, Python, Go, C# и т. д., имеют встроенные сборщики мусора, но в примитивных языках, таких как C/C++, их нет. Мы создадим сборку мусора с помощью подсчета ссылок на C++.
Область статьи
- Что такое сбор мусора? Зачем они нам нужны?
- Почему в C/C++ отсутствует сборка мусора?
- Можем ли мы построить один?
- Сбор мусора через подсчет ссылок
Введение. Что такое сборка мусора? Зачем они нам нужны?
В первом разделе мы рассмотрим, что такое сборка мусора и зачем она нужна.
Наши программы используют память в виде переменных и объектов. Объекты размещаются либо в стеке, либо в куче. В стеках хранятся локально объявленные переменные, такие как «int a = 10;» в кадре стека функции, поэтому, когда функция возвращает значения, они извлекаются из кадра стека, делая их несуществующими. Так что нам не нужна сборка мусора для стека.
Кучи, с другой стороны, разные. Переменная кучи выделяется с помощью функций «new» или «malloc». Объектное пространство, созданное для таких вещей, находится в оперативной памяти. Они должны быть явно освобождены, когда мы закончим с ними, поскольку они переживут область действия и выполнение функции. Для кучи нам нужна функция автоматического восстановления памяти, встроенная в языки программирования, называемая сборщиками мусора. Отсутствие сборщика мусора может привести к утечкам памяти и оборванным указателям.
Почему в C/C++ отсутствует сборка мусора?
- Производительность. Сборка мусора может быть ресурсоемкой и может негативно сказаться на производительности программы. В C/C++ разработчики могут вручную управлять памятью, что может привести к более эффективному использованию ресурсов. C/C++ должен работать на «голом железе» с быстрым временем выполнения.
- Контроль: C/C++ позволяет разработчикам полностью контролировать выделение и освобождение памяти, позволяя им оптимизировать свой код для конкретных случаев использования. При сборке мусора у разработчиков может быть меньше контроля над выделением и освобождением памяти.
- Совместимость: C/C++ часто используется для написания низкоуровневых системных библиотек и драйверов, которые требуют точного контроля над управлением памятью. Сборка мусора может быть несовместима с этими типами приложений.
- Сложность. Реализация сборки мусора на C/C++ может быть сложной, так как требует добавления в язык дополнительного кода. Это может увеличить сложность языка и может не стоить усилий для некоторых разработчиков.
- Устаревший код: C/C++ существует уже давно и имеет большое количество существующих кодовых баз, основанных на ручном управлении памятью. Добавление сборки мусора в язык потенциально может сломать эти основы кода и вызвать проблемы у разработчиков, которые на них полагаются.
Можем ли мы построить его?
Да, можно построить систему сборки мусора для C/C++. Существует несколько сторонних библиотек, предлагающих сборку мусора для C/C++, например сборщик мусора Boehm-Demers-Weiser. Однако эти системы могут работать не со всем кодом C/C++ и могут иметь некоторые потери производительности по сравнению с ручным управлением памятью. Кроме того, реализация сборки мусора в C/C++ может быть более сложной и требовать больше усилий, чем в языках, которые имеют встроенную поддержку сборки мусора.
В C и C++ вы можете реализовать сборку мусора, используя подсчет ссылок, маркировку и очистку, отслеживание сборки мусора и т. д.
Бонус: сборка мусора с помощью подсчета ссылок.
#include <iostream> #include <unordered_map> #include <memory> // A simple garbage collected object class GCObject { public: // Constructor increments the reference count GCObject() : refCount(1) {} // Destructor decrements the reference count virtual ~GCObject() { refCount--; // If the reference count is 0, delete the object if (refCount == 0) { delete this; } } // Increment the reference count void AddRef() { refCount++; } private: int refCount; }; // A garbage collector class class GC { public: // Add an object to the garbage collector static void AddObject(GCObject* obj) { objects[obj] = obj; } // Remove an object from the garbage collector static void RemoveObject(GCObject* obj) { objects.erase(obj); } // Collect garbage by deleting objects with a reference count of 0 static void Collect() { for (auto& [obj, count] : objects) { if (obj->refCount == 0) { delete obj; } } } private: static std::unordered_map<GCObject*, GCObject*> objects; }; // Initialize the static objects map std::unordered_map<GCObject*, GCObject*> GC::objects; int main() { // Create a garbage collected object GCObject* obj = new GCObject(); // Add the object to the garbage collector GC::AddObject(obj); // Remove the object from the garbage collector GC::RemoveObject(obj); // Collect garbage GC::Collect(); return 0; }
В этом классе GCObject
реализуется подсчет ссылок путем поддержки поля refCount
. Конструктор GCObject
увеличивает счетчик ссылок, а деструктор уменьшает его. Если счетчик ссылок становится равным 0, объект удаляет себя.
Класс GC
— это простой сборщик мусора, который поддерживает карту объектов и количество их ссылок. Методы AddObject
и RemoveObject
добавляют и удаляют объекты с карты соответственно. Метод Collect
перебирает объекты на карте и удаляет все объекты со счетчиком ссылок, равным 0.
В двух словах…
В заключение, хотя сборка мусора может быть полезным инструментом для управления памятью в языках программирования, она может отрицательно сказаться на производительности и может быть несовместима с некоторыми типами приложений. Разработчики C/C++ имеют возможность вручную управлять памятью, что может обеспечить больший контроль и потенциально более эффективное использование ресурсов. Однако реализация сборки мусора в C/C++ может быть сложной и не стоит затраченных усилий для некоторых разработчиков. Кроме того, большое количество устаревших кодовых баз, которые полагаются на ручное управление памятью в C/C++, могут создать проблемы для включения сборки мусора в язык.