2008-09-22 8 views
91

Я googled вокруг и нашел большинство людей, выступающих за использование kmalloc, так как вы гарантированно получите смежные физические блоки памяти. Тем не менее, также кажется, что kmalloc может выйти из строя, если не найден нужный физический блок.
Каковы преимущества наличия непрерывного блока памяти? В частности, зачем мне нужно иметь смежный физический блок памяти в системном вызове ? Есть ли причина, по которой я не мог просто использовать vmalloc?
Наконец, если бы я должен был выделить память во время обработки системного вызова, должен ли я указывать GFP_ATOMIC? Является ли системный вызов выполненным в атомном контексте?В чем разница между vmalloc и kmalloc?

GFP_ATOMIC
Распределение является высоким приоритетом и не спит. Это флаг для использования в обработчиках прерываний, внизу половинки и другие ситуации, когда вы не можете спать.

GFP_KERNEL Это нормальное распределение и может блокироваться. Это флаг для использования в коде контекста процесса, когда он безопасен для сна.

+0

Хорошая статья о vmalloc и kmalloc [http://learnlinuxconcepts.blogspot.in/2014/02/linux-memory-management.html](http://learnlinuxconcepts.blogspot.in/2014/02/linux- memory-management.html) – JIN007 2014-02-15 15:35:13

ответ

76

Вам нужно только беспокоиться об использовании физически смежной памяти, если к буферу будет обращаться устройство DMA на физически адресуемой шине (например, PCI). Беда в том, что многие системные вызовы не имеют возможности узнать, будет ли их буфер в конечном итоге передан на устройство DMA: после того, как вы передадите буфер другой подсистеме ядра, вы действительно не можете знать, куда он будет идти. Даже если ядро ​​не использует буфер для DMA сегодня, может сделать это в будущем.

vmalloc часто медленнее, чем kmalloc, так как он может перенаправить буферное пространство в практически непрерывный диапазон. kmalloc никогда не переназначает, хотя если не вызывается с GFP_ATOMIC, то kmalloc может блокировать.

kmalloc ограничен размером буфера, который он может предоставить: 128 КБ *). Если вам нужен действительно большой буфер, вам нужно использовать vmalloc или какой-либо другой механизм, например, резервировать высокую память при загрузке.

*)Это было верно предыдущих ядер. В последних ядрах (я тестировал это на 2.6.33.2) максимальный размер одного километрала до 4 МБ! (Я написал довольно detailed post on this.) — kaiwan

Для системы вызова вам не нужно проходить GFP_ATOMIC в kmalloc(), вы можете использовать GFP_KERNEL. Вы не обработчик прерываний: код приложения вводит контекст ядра с помощью ловушки, это не прерывание.

6

Каковы преимущества наличия непрерывного блока памяти? В частности, почему мне нужно иметь непрерывный физический блок памяти в системном вызове? Есть ли причина, по которой я не мог просто использовать vmalloc?

С «Мне повезёт» Google на vmalloc:

kmalloc является предпочтительным способом, до тех пор, пока вы не нужны очень большие площади. Проблема в том, что если вы хотите сделать DMA с/на какое-то аппаратное устройство, вам нужно будет использовать kmalloc, и вам, вероятно, понадобится больший кусок. Решение заключается в том, чтобы как можно скорее выделить память, до того, как память будет фрагментирована.

+0

Смотрите, я читал это, и это не имеет смысла для меня. Я понимаю, используя kmalloc для __big__ областей; но для небольших распределений, почему бы не использовать vmalloc, чтобы избежать фрагментации физической памяти? – FreeMemory 2008-09-22 17:54:10

+0

Потому что вы должны доверять ядру, чтобы сделать то, что лучше; если он думает, что выделение одного куска лучше, он это сделает. vmalloc - это только когда вы абсолютно * должны иметь непрерывный кусок. – 2008-09-22 17:58:09

+0

Я предполагаю, что это имеет смысл, но кажется нелогичным. kmalloc звучит так, как будто его следует использовать, когда производительность вызывает наибольшую озабоченность (т. е. я не могу пострадать от диска IO). Также, как насчет GFP_ATOMIC? – FreeMemory 2008-09-22 18:00:42

16

Короткий ответ: загрузить Linux Device Drivers и прочитать главу об управлении памятью.

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

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

1

Одним из других отличий является то, что kmalloc вернет логический адрес (иначе вы укажете GPF_HIGHMEM). Логические адреса помещаются в «низкую память» (в первом гигабайте физической памяти) и отображаются непосредственно на физические адреса (используйте макрос __pa для его преобразования). Это свойство подразумевает, что память в километрах - это непрерывная память.

В другой руке Vmalloc может возвращать виртуальные адреса из «высокой памяти». Эти адреса не могут быть преобразованы в физические адреса напрямую (вы должны использовать функцию virt_to_page).

9

Linux Kernel Development от Robert Love (глава 12, стр. 244 в 3-м издании) отвечает на это очень четко.

Да, физически смежная память не требуется во многих случаях. Основной причиной использования kmalloc больше, чем vmalloc в ядре, является производительность. В книге объясняется, что, когда большие куски памяти выделяются с помощью vmalloc, ядро ​​должно отображать физически несмежные куски (страницы) в единую непрерывную область виртуальной памяти. Поскольку память является практически непрерывной и физически несмежной, в таблицу страниц должно быть добавлено несколько сопоставлений между виртуальными и физическими адресами. И в худшем случае будет (размер буфера/размер страницы) Число отображений, добавленных в таблицу страниц.

Это также добавляет давление на TLB (записи кэша, хранящие последние сопоставления виртуальных на физические адреса) при доступе к этому буферу. Это может привести к thrashing.

7

kmalloc() & vmalloc() функции - это простой интерфейс для получения памяти ядра в кусках размера байта.

  1. kmalloc() функция гарантирует, что страницы физически смежные (и практически непрерывные).

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

1

На 32-битной системе, kmalloc() возвращает логический адрес ядра (его виртуальный адрес, хотя), который имеет прямое отображение (на самом деле с постоянным смещением) к физическому адресу. Это прямое отображение гарантирует, что мы получим непрерывный физический кусок ОЗУ. Подходит для DMA, где мы даем только начальный указатель и ожидаем последующего физического отображения после этого для нашей операции.

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