Linux Kernel (Ядро линукса) (часть 2)


Управление кучей

У каждого процесса в Unix есть специфическая область памяти, называемая кучей. Она служит для удовлетворения запросов процесса на динамическую память. Поля start brk и brk дескриптора памяти определяют, соответственно, начальный и конечный адреса этой области.

Для получения и освобождения динамической памяти процесс может воспользоваться следующими API-интерфейсами:
- maiioc (size) — запрашивает size байтов динамической памяти; в случае успешного выделения памяти возвращает линейный адрес первой ячейки;
- caiioc (n, size) — запрашивает массив из п элементов длины size; в случае успешного выделения памяти инициализирует элементы массива нулями и возвращает линейный адрес первого элемента;
- reaiioc (ptr, size) — изменяет размер области памяти, ранее выделенной функциями malloc ИЛИ calloc ;
- free (addr)— освобождает область памяти, выделенную функциями maiioc или caiioc и начинающуюся с адреса addr;
- brk(addr) — напрямую изменяет размер кучи; параметр addr задает новое значение поля current->mm->brk, а возвращаемое значение является новым конечным адресом области памяти (процесс должен проверить, совпадает ли оно с запрошенным значением addr);
- sbrk(incr) — аналогична функции brko, но параметр incr определяет увеличение или уменьшение кучи в байтах.

Функция brk отличается от других перечисленных функций, потому что только она реализована в виде системного вызова. Все остальные реализованы в библиотеке С с использованием функций brk и mmap.

Когда процесс в режиме пользователя делает системный вызов brk , ядро вызывает функцию sys brk(addr). Эта функция вначале проверяет, не попадает ли параметр addr в область памяти, содержащую код процесса. Если это так, она немедленно возвращает управление, потому что куча не может пересекаться с областью, в которой находится код процесса:
mm = current->mm; down_write (&mm->mmap_sem) ; if (addr end_code) { out:up_write (&mm->mmap_sem) ; return mm->brk;}
Поскольку системный вызов brk () работает с областью памяти, он выделяет и освобождает целые страницы. Поэтому функция выравнивает значение addr так, чтобы оно было кратно числу page size, и сравнивает результат со значением поля brk дескриптора памяти:newbrk = (addr + Oxfff) & OxfffffOOO; oldbrk = (mm->brk + Oxfff) & OxfffffOOO; if (oldbrk == newbrk) { mm->brk = addr; goto out;}
Если процесс запросил уменьшение размера кучи, функция sys brk вызывает функцию do munmap , чтобы выполнить эту задачу, а затем возвращает управление:
if (addr brk) {if (!do_munmap(mm, newbrk, oldbrk-newbrk)) mm->brk = addr; goto out;}
Если же процесс попросил увеличить кучу, функция sys brk вначале проверяет, разрешено ли это ему. Если процесс пытается выделить память, превышая свой лимит, функция просто возвращает прежнее значение поля mm->brk, не предоставляя процессу дополнительную память:
rlim = current->signal->rlim[RLIMIT_DATA] . rlim_cur; if (rlim start_data > rlim) goto out;
Затем функция проверяет, не пересечется ли увеличенная куча с другой областью памяти, принадлежащей процессу. Если пересечение возможно, функция возвращает управление, ничего не предпринимая:
if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE) ) goto out;
Если все в порядке, вызывается функция do brk . Если она возвращает значение oldbrk, значит, выделение памяти произошло успешно, и функция sys brk возвращает значение addr; в противном случае она возвращает старое значение mm->brk:
if (do_brk(oldbrk, newbrk-oldbrk) == oldbrk) mm->brk = addr; goto out;
Функция do brk ЭТО фактически упрощенная версия функции dojnmap ,
которая работает только с анонимными областями памяти. Ее вызов эквивалентен вызову:
dojnmap(NULL, oldbrk, newbrk-oldbrk, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0)
Функция do_brk работает немного быстрее, чем dojnmap о, потому что опускает некоторые проверки полей объекта-области памяти исходя из предположения, что эта область памяти не отображает файл с диска.

Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга...

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...