Привет! Когда речь заходит о динамическом управлении памятью в Linux, мы имеем дело с несколькими разными подходами, каждый из которых имеет свои плюсы и минусы.
В этой статье разберем три аллокатора памяти ядра: SLAB, SLOB, а также SLUB.
Зачем вообще нужны slab-менеджеры?
Ядро Linux работает с множеством объектов, которые занимают память, но их размер может сильно варьироваться. Выделение памяти через обычный механизм работы с кучей (как malloc
в юзер пространстве) было бы слишком затратным и приводило бы к значительной фрагментации. Slab‑менеджеры были разработаны для лучшего управления памятью, минимизации фрагментации и ускорения работы с мелкими объектами, которые часто создаются и уничтожаются ядром.
Основная идея: slab как контейнер
SLAB основан на концепции кэшей, в которых хранятся объекты определенного размера. Эти объекты размещаются в блоках памяти, которые называются slabами. Каждый slab содержит несколько объектов одного типа и может находиться в одном из трёх состояний:
-
Пустой (empty) — все объекты свободны.
-
Частично заполненный (partial) — некоторые объекты заняты.
-
Полностью заполненный (full) — все объекты заняты.
Когда ядру требуется объект, оно сначала пытается найти свободный объект в частично заполненных slab’ах. Если таких объектов нет, выделяется новый slab.
Структура slab’а
Каждый slab состоит из нескольких страниц памяти (по дефолту 4 КБ), которые делятся на маленькие кусочки (объекты). Когда объект освобождается, он не удаляется физически, а возвращается в slab, чтобы его можно было использовать повторно. Это снижает накладные расходы на выделение и освобождение памяти.
struct kmem_cache { unsigned int object_size; // Размер объекта unsigned int num; // Количество объектов в slab'е struct list_head slabs_full, slabs_partial, slabs_empty; // Списки slab'ов };
SLAB использует три списка:
-
slabs_full — все объекты в этих slab’ах заняты.
-
slabs_partial — slab’ы, в которых есть свободные объекты.
-
slabs_empty — пустые slab’ы, которые можно использовать для новых объектов.
Допустим, ядру нужен объект размером 32 байта. Если в частично заполненных slab’ах есть свободное место, оно выделяется. Если же места нет, создаётся новый slab. Вот как это выглядит:
struct kmem_cache *my_cache; my_cache = kmem_cache_create("my_cache", sizeof(struct my_struct), 0, SLAB_HWCACHE_ALIGN, NULL); void *obj = kmem_cache_alloc(my_cache, GFP_KERNEL); // используем объект kmem_cache_free(my_cache, obj); // возвращаем его в кэш
SLAB хорошо подходит для серверных систем с большим количеством параллельных запросов.
Как работает SLOB?
SLOB — это супер минималистичный аллокатор, который, в отличие от SLAB, ориентирован на минимальные накладные расходы и максимальную экономию памяти. Он напоминает работу стандартной кучи, как malloc
в пользовательском пространстве. Внутри SLOB работает с небольшими блоками памяти, что делает его очень простым и эффективным для устройств с ограниченными ресурсами.
Как это работает?
-
Свободные блоки (Free List). В SLOB нет кэшей, как в SLAB, и объекты выделяются динамически из блоков памяти. Аллокатор хранит список свободных блоков, из которых выделяются объекты. Когда объект освобождается, он возвращается в свободный список, что делает алгоритм простым, но приводит к фрагментации.
-
Аллокация памяти. SLOB работает как простая куча, выделяя ровно столько памяти, сколько нужно. Если фрагментация слишком высока и не удаётся найти подходящий блок, выделяется новый.
-
Экономия памяти. Поскольку SLOB выделяет ровно столько памяти, сколько необходимо, без использования больших slab’ов, он оптимален для систем, где важно экономить каждый байт.
Пример простого выделения памяти с использованием SLOB:
void *data = slob_alloc(128); if (data) { // Работаем с выделенной памятью slob_free(data); // Освобождаем память }
SLOB выделяет блок, минимально необходимый для объекта
В чем разница между SLAB и SLOB?
Характеристика |
SLAB |
SLOB |
---|---|---|
Подходит для |
Высоконагруженные системы |
Встраиваемые системы |
Управление памятью |
Использует кэши для объектов одинакового размера |
Прямое управление блоками памяти |
Фрагментация |
Минимальная за счёт использования slab’ов |
Высокая из-за простого управления блоками |
Производительность |
Высокая за счёт кэширования объектов и минимальной фрагментации |
Низкая при большом количестве мелких объектов |
Накладные расходы |
Высокие, из-за сложного механизма кэширования и поддержки SMP |
Минимальные, за счёт простоты реализации |
SLUB
SLUB использует упрощённую структуру по сравнению со SLAB. Он не поддерживает такие понятия, как кэш объектов, и не хранит метаданные о каждом объекте в отдельной структуре. Вместо этого SLUB хранит свободные блоки памяти прямо внутри slab’ов.
Каждый процессор имеет свой собственный активный slab, что оптимизирует работу многопроцессорных систем и минимизирует задержки при выделении памяти.
Пример структуры в SLUB:
struct kmem_cache_cpu { void **freelist; // Список свободных блоков памяти struct page *page; // Текущая страница slab'а };
В этом примере freelist
— это указатель на свободные блоки памяти, которые могут быть быстро выделены для новых объектов. Вместо создания сложных кэшей, как в SLAB, SLUB просто хранит указатели на свободные объекты прямо в slab’ах.
Что выбрать
Динамическое управление памятью в Linux реализовано через несколько аллокаторов, каждый из которых решает свои задачи. SLAB дает высокую производительность за счёт кэширования объектов и минимизации фрагментации, что идеально подходит для серверных систем с высокой нагрузкой. SLOB фокусируется на экономии памяти и минимальных накладных расходах, что делает его лучшим выбором для встраиваемых устройств с ограниченными ресурсами. SLUB является упрощённой и улучшенной версией SLAB, дает более быструю работу, особенно в многопроцессорных системах.
Научиться профессиональному подбору конфигураций, управлению процессами, обеспечению безопасности, развертыванию, настройке и обслуживанию сетей можно на онлайн‑курсе «Administrator Linux. Professional» под руководством экспертов-практиков.
ссылка на оригинал статьи https://habr.com/ru/articles/853252/
Добавить комментарий