Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Функции для освобождения фреймов страниц



Существует много функций для освобождения фреймов страниц: два макроса и две функ­
ции, для которых они служат обертками. Рис. 4.4 демонстрирует иерархию вызова функ­
ций, связанных с освобождением страниц. Эти функции также можно разделить на две
группы. На этот раз разделение проводится по типу получаемых параметров. Первая
группа, включающая__ f ree_page () и_____ f ree_pages (), получает указатель на опи­
сатель страницы, связанный с освобождаемыми страницами. Вторая группа,
f ree_page () и f ree_pages (), получает адрес первой освобождаемой страницы.

 

 

 

 

 

 

 

 

 

 

 

 

 

           
  free_page() _free_pages()    
   
         
  free_page() free_pages()    
   
         

Рис. 4.4. Иерархия вызова *free_page*0

Макросы __ f ree_page () и f ree_page () освобождают одну страницу. Они

передают 0 в качестве порядка освобождаемой страницы в функцию, выполняющую ос­
новную работу в__ f ree_page () и f ree_page () соответственно:

include/linux/gfp.h

94 #define _ free_page(page) _ free_pages((page), 0)

95 tdefine free_page(addr) free_pages((addr), 0)


4.3 Фреймы страниц



В конце концов f ree_page () вызывает______ free_pages_bulk(), являющуюся

функцией реализации в Linux системы близнецов (buddy system). Мы рассмотрим совме­стную систему более подробно в следующем подразделе.

Система близнецов (buddy system)

При выделении и освобождении фреймов страниц, система сталкивается с проблемой фрагментации памяти, называемой внешней фрагментацией (external fragmentation). Это происходит, когда доступные фреймы страниц оказываются разбросаны по памяти таким образом, что невозможно выделить непрерывную последовательность страниц достаточной длины для удовлетворения запроса программы. При этом доступные фрей­мы страниц перемежаются одной или несколькими занятыми фреймами страниц, ко­торые их разрывают. Уменьшить внешнюю фрагментацию можно несколькими способа­ми. Linux использует реализацию алгоритма менеджера памяти, называемую системой близнецов (buddy system).

Система близнецов содержит список доступных блоков памяти. Каждый список ука­зывает на блок памяти разного размера, каждый из которых равен степени двойки. Ко­личество списков зависит от реализации. Фреймы страниц выделяются из списка свобод­ных блоков наименьшего доступного размера. Система придерживает наибольшие дос­тупные блоки для обслуживания больших запросов. Когда возвращаются выделенные блоки, система близнецов выполняет поиск свободных списков доступных блоков памяти, имеющих тот же размер, который имеет и возвращаемый блок. Если любой из доступных блоков прилегает к возвращаемому блоку, они объединяются блок в 2 раза большего раз­мера. Эти блоки (возвращаемый и следующий за ним доступный) называются близнеца­ми, откуда и происходит название «система близнецов». При этом ядро проверяет, чтобы блоки большего размера стали доступными сразу после освобождения фрейма страницы.

Теперь посмотрим на функции, реализующие систему близнецов в Linux. Функция
выделения фрейма страницы__ alloc_pages () (mm/page__alloc. с). Фрейм страни­
цы освобождается с помощью функции__ f ree_pages_bulk ():

mm/page_alloc.с

585 struct page * fastcall

586 __ alloc_pages(unsigned int gfp_mask, unsigned int order,

587 struct zonelist *zonelist)

588 {

589 const int wait = gfp_mask & _ GFP__WAIT;

590 unsigned long min;

591 struct zone **zones;

592 struct page *page;

593 struct reclaim_state reclaim_state;

594 struct task_struct *p = current;

595 int i;



Глава 4 • Управление памятью


596 int alloc__type;

597 int do_retry; 598

599 might_sleep_if(wait);
600

601 zones = zonelist-> zones;

602 if (zones[0] == NULL) /* В списке зон нет зон */

603 return NULL;
604

605 alloc_type = zone_idx(zones[0]);

608 for (i = 0; zones [i]! = NULL; i++) {

609 struct zone *z = zones[i];
610

611 min = (l«order) + z-> protection[alloc_type];

617 if (rt_task(p))

618 min -= z-> pages_low » 1;
619

620 if (z-> free_pages > = min ||

621 (! wait & & z-> free_pages > = z-> pages__high) ) {

622 page = buffered_rmqueue(z, order, gfp_mask);

623 if (page) {

624 zone_statistics(zonelist, z);

625 goto got_pg;

626 }

627 }

628 }
629

63 0 /* у нас мало памяти, и мы не смогли найти то, что нам нужно */

631 for (i = 0; zones[i]! = NULL; i++) {

632 wakeup_kswapd(zones [i]);
633

634 /* Снова проходим по списку зон, с учетом _ GFP_HIGH */

635 for (i = 0; zones[i]! = NULL; i++) {

636 struct zone *z = zones[i];
637

638 min = (l«order) + z-> protection[alloc_type];
639

640 if (gfp_mask & _ GFP_HIGH)

641 min -= z-> pages_low » 2;

642 if (rt_task(p))

643 min -= z-> pages_low » 1;
644

645 if (z-> free_pages > = min ||

646 (! wait & & z-> free_pages > = z-> pages_high)) {


Фреймы страниц



647 page = buffered_rmqueue(z, order, gfp_mask);

648 if (page) {

 

649 zone_statistics(zonelist, z);

650 goto got_pg;

651 }

652 }

653 }

72 0 nopage:

721 if (! (gfp_mask & _ GFP_NOWARN) & & printk_ratelimit () ) {

722 printk(KEKN_WAKNING " %s: page allocation failure."

723 * ordered, mode: 0x%x\n" ,

724 p-> comm, order, gfp_mask);

725 dump_s tack();

726 }

727 return NULL;

728 got_pg:

729 kernel_map_pages(page, 1 « order, 1);

73 0 return page;
731 }

Система близнецов в Linux разделена на зоны, что означает, что список поддержи­ваемых доступных фреймов разделен на зоны. При этом каждый поиск свободного фрей­ма страниц может выполняться в одной из трех возможных зон, из которых можно по­лучить фреймы страниц.

Строка 586

Целочисленное значение gf p_mask позволяет вызывающему__ alloc_pages ()

коду определять способ поиска фреймов страниц (модификаторов действия). Воз­можные значения определены в include/linux/gfp.h и перечислены в табл. 4.2.

Таблица 4.2. Модификаторы действия для gfpjnask при выделении страниц памяти

Флаг Описание

__ GFP_WAIT Позволяет ядру блокировать процесс, ожидающий фрейм страницы.

Пример его использования можно увидеть в строке 537 page_alloc. с

__ GFP_COLD Требуется кеширование холодных страниц

__ GFP_HIGH Фрейм страницы можно найти в экстренном пуле памяти

__ GFP_IO Возможно выполнение передачи ввода-вывода

__ GFP_FS Позволяет вызвать низкоуровневые операции файловой системы



Глава 4 • Управление памятью


Таблица 4.2. Модификаторы действия для gfpjnask при выделении страниц памяти (Окончание)


GFP_NOWARN

_GFP_REPEAT _GFP_NORETRY _GFP_DMA _GFP_HIGHMEM


При ошибке выделения фрейма страницы функция выделения посылает предупреждение об ошибке. Если выбран этот модификатор, сообщение не выводится. Пример применения этого флага можно увидеть в строках 665-666 page_alloc. с

Повторная попытка выделения

Запрос не требуется повторять из-за возможности ошибки

Фрейм страницы находится в ZONE_DMA

Фрейм страницы находится в ZONE_HIGHMEM


В табл. 4.3 представлены указатели на список зон, соответствующих модификаторам из gf p_mask.

Таблица 4.3. Список зон


Флаг


Описание


GFP__USER Означает, что память выделяется не в пространстве ядра

GFP_KERNEL Означает, что память выделяется в пространстве ядра

GFP_ATOMIC Используется в обработчиках прерываний с помощью вызова kmalloc,

так как предполагается, что выделитель памяти не засыпает

GFP_DMA Означает, что память выделяется из ZONE_DMA

Строка 599

Функция might_sleep_if () получает значение переменной wait, хранящей ло­
гический бит операции AND для gfp__mask и значения ___________ GFP_WAIT. Значение

wait равно 0, если_______ GFP_WAIT не установлено, и 1, если установлено. Если при

конфигурации ядра включена проверка сна при циклической блокировке (в меню Kernel Hacking), эта функция позволяет ядру блокировать текущий процесс на зна­чение времени задержки.

Строки 608-628

В этом блоке мы проходим список описателей зон и ищем зону с достаточным для удовлетворения запроса количеством свободных страниц. Если количество свобод­ных страниц удовлетворяет требуемому или если процессу разрешены ожидания, а количество свободных страниц больше либо равно верхнему пороговому значе­нию зоны, вызывается функция buf f ered_rmqueue ().


Фреймы страниц



Функция buf f ered__rmqueue () получает три аргумента: описатель зоны с доступными фреймами страниц, порядок количества требуемых фреймов страниц и температуру требуемых страниц.

Строки 631-632

Если мы попали в этот блок, мы не можем выделить страницу, потому что у нас слишком мало доступных фреймов страниц. Здесь предпринимается попытка вернуть фреймы страниц для удовлетворения запроса. Функция wakeup_ kswapd () выполняет эти действия и корректирует зоны с соответствующими фреймами страниц. При этом обновляются описатели зон.

Строки 635-653

После попытки возвращения фреймов страниц в предыдущем блоке кода мы снова проходим по зонам и ищем свободные фреймы страниц.

Строки 720-727

В этот блок кода мы попадаем, когда понимаем, что доступных фреймов страниц нет. Если выбран модификатор GFP_NOWARN, функция выводит сообщение об ошибке выделения страницы, включающее имя команды, вызванной для текуще­го процесса, порядок требуемых фреймов страниц и применяемую к запросу gf p_mask. Эта функция возвращает NULL.

Строки 728-730

Переход в этот блок кода выполняется после того, как требуемые страницы об­наружены. Функция возвращает адрес описателя страницы. Если требуется более одного фрейма страницы, она возвращает адрес описателя страницы для первого выделенного фрейма страницы.

При возвращении блока памяти система близнецов старается объединить их в блок
большего размера, если доступен близнец такого же порядка. Это действие выполняет
функция__ f ree_pages_bulk (). Посмотрим, как она работает.

mm/page_alloc.с

178 static inline void _ free_pages_bulk (struct page *page,

struct page *base,

179 struct zone *zone, struct free_area *area, unsigned long mask,

180 unsigned int order)

181 {

182 unsigned long page_idx, index;
183

184 if (order)

185 destroy_compound_page(page/ order);

186 page_idx = page - base;



Глава 4 • Управление памятью


187 if (page_idx & -mask)

188 BUG ();

189 index = page_idx » (1 + order);
190

191 zone-> free_j? ages -= mask;

192 while (mask + (1 « (MAX_ORDER-l))) {

193 struct page *buddyl/ *buddy2;
194

195 BUG_ON(area > = zone-> free_area + MAX_ORDER);

196 if (! _ test_and_change_bit(index, area-> map))

206 buddyl = base + (page_idx Л -mask);

2 07 buddy2 = base + page_idx;

208 BUG__ON(bad_range(z one, buddyl));

209 BUG_ON(bad_range(z one, buddy2));

210 list_del(& buddyl-> lru);

211 mask «= 1;

212 area++;

213 index »= 1;

214 page_idx & = mask;

215 }

216 list_add(& (base + page_idx)-> lru, & area-> free_list);

217 }

Строки 184-215

Функция___ free_pages_bulk() перебирает размеры блоков, соответствующих

каждому из списков свободных блоков. (MAX_ORDER - это порядок блока наиболь­шего размера.) Для каждого порядка, и пока не будет достигнут максимальный

порядок или найден наименьший близнец, она вызывает ___ test_and_

change_bit (). Эта функция проверяет, выделена ли страница близнеца для возвращаемого блока. Если это так, мы прерываем цикл. Если нет, она смотрит, можно ли найти близнеца с большим порядком, с которым можно объединить наш освобождаемый блок фреймов страниц.

Строка 216

Свободный блок вставляется в соответствующий список свободных фреймов страниц.

Выделение секций

Мы говорили, что страницы являются для менеджера памяти базовой единицей памяти. Тем не менее обычно процесс требует память указанного порядка байтов, а не порядка страниц. Для удовлетворения запросов по выделению меньших объемов памяти исполь-


Выделение секций



зуется вызов функции kmalloc (), ядро реализует выделитель секций (slab allocator), являющийся слоем менеджера памяти, работающего с затребованными страницами.

Выделитель секций пытается уменьшить затраты на выделение, инициализацию, уничтожение и освобождение областей памяти, поддерживая кеш недавно использован­ных областей памяти. Этот кеш хранит выделенные и инициализированные области памя­ти, готовые к размещению. Когда пославший требование процесс больше не нуждается в области памяти, эта область возвращается в кеш.

На практике выделитель секций содержит несколько кешей, каждый из которых хра­нит области памяти разного размера. Кеши могут быть специализированными (special­ized) или общего назначения (general purpose). Например, описатель процесса task_struct хранится в кеше, поддерживаемом выделителем секций. Область памяти, занимаемая этим кешем равна sizeof (task_struct). Аналогично хранятся в кеше структуры данных inode и dentry. Кеши общего назначения создаются из областей памяти предопределенного размера. Области памяти могут иметь размер 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65535 и 131072 байта1.

Если мы запустим команду cat /proc/stabinf о, будет выведен список сущест­вующих кешей выделителя. В первой колонке вывода мы можем увидеть имена структур данных и группу элементов в формате size-*. Первый набор соответствует специали­зированным объектам кеша; набор букв соответствует кешам, хранящим объекты общего назначения указанного размера.

Кроме этого, вы можете заметить, что кеши общего назначения имеют два вхождения одинакового размера, у одного из которых в конце стоит DMA. Это происходит потому, что области памяти могут быть затребованы как из обычной зоны, так и из зоны DMA. Выде­литель секций поддерживает кеши обеих типов памяти для удовлетворения всех запросов. Рис. 4.5 демонстрирует вывод /proc/slabinf о, где видны кеши обеих типов памяти.

В свою очередь, кеш делится на контейнеры, называемые секциями (slabs). Каждая секция составляется из одного или более прилегающих фреймов страниц, из которых вы­деляются области памяти меньшего размера. Поэтому мы будем говорить, что секции со­держат объекты. Сами объекты представляют собой интервалы адресов предопределенно­го размера внутри фрейма страницы, который принадлежит к данной секции. Рис. 4.6 де­монстрирует анатомию выделителя секций.

Выделитель секций использует три главные структуры для поддержания информа­ции об объекте: описатель кеша, называемый kmem_cache; общий описатель кеша, на­зываемый cache_size, и выделитель секции, называемый slab. Рис. 4.7 показывает об­щую картину связей между всеми описателями.

1 Все кеши общего назначения для повышения производительности выравниваются по L1.



Глава 4 • Управление памятью


 


 

size-131072(DMA) : tunables slab data
size-131072 : tunables slabdata
size-65536 (DMA) : tunables slabdata
size-65536 : tunables slabdata
size-32768 (DMA) : tunables slabdata
size-32768 : tunables slabdata
size-16384 (DMA) : tunables slabdata
size-16384 : tunables slabdata
size-8192(DMA) /%A : tunables slabdata
size-8192 : tunables slabdata
size-4096 (DMA) : tunables slabdata
size-4096 : tunables slabdata
size-204cV(DMA) : tunables slabdata
size.-2048 : tunables slabdata
siz6-1024(DMA) : tunables slabdata
size-1024 : tunables slabdata
size-512(DMA) : tunables slabdata
size-512 : tunables slabdata
size-256 (DMA) : tunables slabdata
size-256 : tunables slabdata
size-128(DMA) : tunables slabdata
size-128 : tunables slabdata
size-64 (DMA) : tunables slabdata
size-64 : tunables slabdata

 


Рис. 4.5. cat /proc/slabinfo

Секция Объекты


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-03-25; Просмотров: 874; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.053 с.)
Главная | Случайная страница | Обратная связь