Выделение Slab - это механизм управления памятью, предназначенный для эффективного распределения памяти объектов. По сравнению с более ранними механизмами, он уменьшает фрагментацию, вызванную выделением и освобождением. Этот метод используется для сохранения выделенной памяти, содержащей объект данных определенного типа, для повторного использования при последующем распределении объектов того же типа. Он аналогичен пулу объектов , но применяется только к памяти, а не к другим ресурсам.
Размещение Slab было впервые введено в ядре Solaris 2.4 Джеффом Бонвиком. В настоящее время он широко используется во многих Unix и Unix-подобных операционных системах, включая FreeBSD и Linux.
Основная причина для размещения перекрытий - что стоимость (в процессоре) инициализации и уничтожения объектов данных ядра может перевесить стоимость выделения для них памяти. Поскольку ядро часто создает и удаляет объекты, накладные расходы на инициализацию могут привести к значительному снижению производительности. Кэширование объектов приводит к менее частому вызову функций, которые инициализируют состояние объекта: когда выделенный блоком объект освобождается после использования, система распределения блоков обычно сохраняет его в кэше (вместо того, чтобы выполнять работу по его уничтожению), готовым для повторного использования в следующий раз объект этого типа необходим (что позволяет избежать работы по созданию и инициализации нового объекта).
При распределении блоков данных кэш для определенного типа или размера объекта данных имеет ряд предварительно выделенных блоков памяти; внутри каждой плиты есть блоки памяти фиксированного размера, подходящие для объектов. Распределитель slab отслеживает эти фрагменты, поэтому, когда он получает запрос на выделение памяти для объекта данных определенного типа, обычно он может удовлетворить запрос свободным слотом (фрагментом) из существующего slab. Когда распределителю предлагается освободить память объекта, он просто добавляет слот в список свободных (неиспользуемых) слотов содержащего слэба. Следующий вызов для создания объекта того же типа (или выделения памяти того же размера) вернет этот слот памяти (или какой-либо другой свободный слот) и удалит его из списка свободных слотов. Этот процесс устраняет необходимость в поиске подходящего пространства памяти и значительно снижает фрагментацию памяти. В этом контексте блок - это одна или несколько смежных страниц в памяти, содержащих предварительно выделенные фрагменты памяти.
Для понимания алгоритма распределения блоков необходимо определить и объяснить некоторые термины:
Когда программа устанавливает кэш, она выделяет некоторое количество объектов для slab, связанных с этим кешем. Это количество зависит от размера связанных плит.
Перекрытия могут находиться в одном из следующих состояний:
Первоначально система помечает каждую плиту как «пустую». Когда процесс вызывает новый объект ядра, система пытается найти свободное место для этого объекта на частичном слэбе в кэше для этого типа объекта. Если такого расположения не существует, система выделяет новый блок из смежных физических страниц и назначает его кэш-памяти. На этой плите выделяется новый объект, и его расположение помечается как «частичное».
Распределение происходит быстро, потому что система строит объекты заранее и легко размещает их из плиты.
Slab - это величина, на которую кэш может увеличиваться или уменьшаться. Он представляет собой одно выделение памяти для кэша с машины, размер которого обычно кратен размеру страницы. Плита должна содержать список свободных буферов (или bufctls), а также список выделенных буферов (в случае большого размера плиты).
Они предназначены для кешей, в которых хранятся объекты, размер которых составляет не менее 1/8 размера страницы для данной машины. Причина того, что большие плиты имеют разную компоновку по сравнению с маленькими плитами, заключается в том, что они позволяют лучше упаковывать большие плиты в единицы размера страницы, что помогает с фрагментацией. Slab содержит список bufctl, которые являются просто контроллерами для каждого буфера, который может быть выделен (буфер - это память, которую будет использовать пользователь slab-распределителя).
Маленькие плиты содержат объекты, размер которых меньше 1/8 размера страницы для данной машины. Эти небольшие блоки необходимо оптимизировать дальше от логического макета, избегая использования bufctls (которые были бы такими же большими, как и сами данные, и вызывали бы гораздо большее использование памяти). Небольшой блок представляет собой ровно одну страницу и имеет определенную структуру, которая позволяет избежать ошибок. Последняя часть страницы содержит «заголовок плиты», который представляет собой информацию, необходимую для удержания плиты. Начиная с первого адреса этой страницы, имеется столько буферов, сколько может быть выделено без перехода в заголовок slab в конце страницы.
Вместо использования bufctls мы используем сами буферы для хранения свободных ссылок на список. Это позволяет обойти bufctl небольшого слэба.
slabtop
для отображения информации кэша slab ядра в реальном времени