Этот документ описывает основные компоненты нашей системы управления памятью, включая архитектуру аллокатора, алгоритм выделения памяти, механизм пометки живых объектов, а также основные структуры данных.
Наша система использует собственный аллокатор, который работает с фиксированными чанками памяти (обычно 4096 байт). Внутри каждого чанка память разбивается на блоки для маленьких объектов. Для эффективного управления свободными блоками используется механизм free lists или внешнее хранилище для очень маленьких блоков (например, 4 байта). Центральным элементом является Memory Manager (memManager), который отвечает за:
- Запрос новых чанков у операционной системы.
- Разбиение чанков на блоки фиксированного размера.
- Управление свободными блоками посредством free lists.
Во время сборки мусора используется алгоритм mark-sweep, который помечает живые объекты, сканируя корневые указатели (со стека, регистров и статических данных), а затем проходит по куче, используя наши метаданные для определения границ объектов.
Описание:
Чанк – это большой непрерывный блок памяти (обычно 4096 байт), выделяемый у операционной системы.
Назначение:
Чанки служат основным источником памяти для небольших объектов. Каждый чанк разбивается на блоки фиксированного размера.
Ключевые функции:
- Выделение чанка: При исчерпании свободных блоков определённого размера выделяется новый чанк и разбивается на блоки.
-
- Доступ к объектам: Каждый блок в чанке может быть получен по индексу (например, через функцию
chunk.getObject(i)).
- Доступ к объектам: Каждый блок в чанке может быть получен по индексу (например, через функцию
Описание:
Free lists управляют доступными (свободными) блоками для маленьких объектов. При выделении нового чанка свободные блоки добавляются в free lists.
Назначение:
Они позволяют быстро выделять память, отслеживая свободные блоки фиксированного размера.
Реализация:
- Встроенный free list: Если блок достаточно велик для хранения указателя (например, ≥
sizeof(void*)), он может содержать полеnextдля формирования связанного списка. - Внешний free list: Для очень маленьких блоков (например, 4 байта) можно использовать внешнюю структуру (например, std::set), чтобы хранить адреса свободных блоков.
Поведение:
Free list обеспечивает выдачу блоков в определённом порядке – например, при выделении возвращается блок с наименьшим адресом (самый левый блок).
Описание:
Memory Manager – центральный компонент, координирующий выделение памяти, создание чанков и управление free lists.
Обязанности:
- Управление чанками: Выделяет новые чанки, когда свободные блоки определённого размера исчерпаны.
- Регистрация free lists: Поддерживает отображение (например,
std::unordered_map<size_t, FreeList>) между размерами объектов и соответствующими free lists. - Интерфейс аллокации/освобождения: Предоставляет низкоуровневые функции для выделения памяти, которые используются выше по уровню API.
Процесс сборки мусора реализован по схеме mark-sweep:
-
Сканирование корней: Сборщик сканирует регистры, стек и статические данные для поиска потенциальных указателей. Каждый найденный кандидат проверяется с помощью метаданных (например, через malloc‑tables и jump‑tables), чтобы определить, принадлежит ли он выделенной области памяти.
-
Фаза пометки (Mark):
Для каждого найденного указателя сборщик определяет соответствующий объект (используя его начальный адрес и размер) и помечает его как живой. Если объект находится в чанке, информация о нем извлекается через структуры Memory Manager. -
Фаза очистки (Sweep):
После фазы пометки сборщик проходит по куче (или free lists) и освобождает память от объектов, которые не были помечены как живые.
Наша система предоставляет минимальный API для выделения памяти:
-
gc_new<T>(Args&&... args)
Выделяет и конструирует один объект типаTс помощью placement new. Эта функция использует memManager для получения свободного блока размеромsizeof(T). -
gc_new_array<T>(std::size_t count, Args&&... args)Выделяет массив изcountобъектов типаT. Функция пытается зарезервировать непрерывную последовательность блоков из free lists. Если такая последовательность найдена, выполняется placement new для каждого элемента, а информация (начальный адрес, количество элементов, размер элемента) сохраняется в таблице массивов для последующей обработки сборщиком мусора.
-
Оптимизация выделения непрерывной памяти:
Исследовать методы резервирования непрерывных блоков при выделении массива, если блоки выделяются по отдельности. -
Реализовать merge для chuncks одного типа
Для того чтобы гарантировать непрерывность хранения массивов в памяти -
Улучшение управления free lists:
Оценить производительность различных реализаций free lists (встроенной vs. внешней) для очень маленьких блоков. -
Тестирование и бенчмаркинг:
Разработать набор тестов и бенчмарков для валидации и сравнения производительности выделения памяти и сборки мусора.