Scroll to navigation

MREMAP(2) Руководство программиста Linux MREMAP(2)

ИМЯ

mremap - изменяет отображение адреса виртуальной памяти

СИНТАКСИС

#define _GNU_SOURCE         /* Смотрите feature_test_macros(7) */
#include <sys/mman.h>
void *mremap(void *old_address, size_t old_size,
             size_t new_size, int flags, ... /* void *new_address */);

ОПИСАНИЕ

Вызов mremap() увеличивает (или уменьшает) размер существующего отображения памяти, при необходимости, перемещая его (это контролируется аргументом flags и доступным виртуальным адресным пространством).

В old_address указывается старый адрес блока виртуальной памяти, который вы хотите изменить. Заметим, что old_address должен быть выровнен по границе страницы. В old_size задаётся старый размер блока виртуальной памяти. В new_size задаётся запрашиваемый размер блока виртуальной памяти после изменения. Описание необязательного пятого аргумента new_address смотрите далее в параграфе о MREMAP_FIXED.

Если значение old_size равно нулю и old_address указывает на общее отображение (смотрите mmap(2) MAP_SHARED), то mremap() создаст новое отображение тех же страниц.Размер нового отображения будет равен значению new_size, а расположение можно указать в new_address; смотрите описание MREMAP_FIXED далее. Если новое отображение запрашивается через этот метод, то также должен быть указан флаг MREMAP_MAYMOVE.

Аргумент битовой маски flags может быть равен 0 или содержать следующие флаги:

По умолчанию, если для расширения отображения недостаточно пространства в текущем расположении, то вызов mremap() завершается с ошибкой. Если указан флаг, то, если нужно, ядру разрешается переместить отображение на новый виртуальный адрес. Если отображение перемещено, то абсолютные указатели в старом расположении отображения становятся недействительными (должно быть выполнено смещение относительно начального адреса отображения).
Этот флаг играет ту же роль, что и MAP_FIXED для mmap(2). Если указан этот флаг, то mremap() учитывает пятый аргумент void *new_address, в котором задан выровненный на страницу адрес, куда должно быть перемещено отображение. Все предыдущие отображения в адресном диапазоне, задаваемом new_address и new_size, удаляются.
If MREMAP_FIXED is specified, then MREMAP_MAYMOVE must also be specified.
This flag, which must be used in conjunction with MREMAP_MAYMOVE, remaps a mapping to a new address but does not unmap the mapping at old_address.
The MREMAP_DONTUNMAP flag can be used only with private anonymous mappings (see the description of MAP_PRIVATE and MAP_ANONYMOUS in mmap(2)).
After completion, any access to the range specified by old_address and old_size will result in a page fault. The page fault will be handled by a userfaultfd(2) handler if the address is in a range previously registered with userfaultfd(2). Otherwise, the kernel allocates a zero-filled page to handle the fault.
The MREMAP_DONTUNMAP flag may be used to atomically move a mapping while leaving the source mapped. See NOTES for some possible applications of MREMAP_DONTUNMAP.

Если сегмент памяти, указанный old_address и old_size, заблокирован (с помощью mlock(2) или подобного вызова), то эта блокировка останется при изменении/перемещении сегмента. Следовательно, количество заблокированной процессом памяти может измениться.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении mremap() возвращается указатель на новую виртуальную область памяти. При ошибке, возвращается значение MAP_FAILED (то есть (void *) -1), а errno устанавливается в соответствующее значение.

ОШИБКИ

Вызывающий пытается расширить заблокированный сегмент памяти, но это невозможно без превышения предела ресурса RLIMIT_MEMLOCK.
Один из адресов в диапазоне от old_address до old_address+old_size является некорректным адресом виртуальной памяти для этого процесса. Также вы можете получить EFAULT даже если существующие отображения покрывают всё запрошенное адресное пространство, но имеют различные типы.
Указан недопустимый аргумент. Возможные причины:
  • не выровнено значение адреса old_address;
  • a value other than MREMAP_MAYMOVE or MREMAP_FIXED or MREMAP_DONTUNMAP was specified in flags;
  • значение new_size равно нулю;
  • некорректное значение new_size или new_address;
  • новый диапазон адресов, указанный new_address и new_size, перекрывает старый диапазон адресов, указанный old_address и old_size;
  • MREMAP_FIXED or MREMAP_DONTUNMAP was specified without also specifying MREMAP_MAYMOVE;
  • MREMAP_DONTUNMAP was specified, but one or more pages in the range specified by old_address and old_size were not private anonymous;
  • MREMAP_DONTUNMAP was specified and old_size was not equal to new_size;
  • значение old_size равно нулю и old_address не указывает на общее отображение (но смотрите ДЕФЕКТЫ);
  • значение old_size равно нулю и не указан флаг MREMAP_MAYMOVE.
Not enough memory was available to complete the operation. Possible causes are:
  • Область памяти не может быть расширена от текущего виртуального адреса и в flags не указано значение MREMAP_MAYMOVE. Или недостаточно свободной (виртуальной) памяти.
  • MREMAP_DONTUNMAP was used causing a new mapping to be created that would exceed the (virtual) memory available. Or, it would exceed the maximum number of allowed mappings.

СООТВЕТСТВИЕ СТАНДАРТАМ

Данный вызов существует только в Linux и не должен использоваться в программах, которые должны быть переносимыми.

ЗАМЕЧАНИЯ

mremap() изменяет отображение между виртуальными адресами и страницами памяти. Это можно использовать при реализации очень эффективной функции realloc(3).

In Linux, memory is divided into pages. A process has (one or) several linear virtual memory segments. Each virtual memory segment has one or more mappings to real memory pages (in the page table). Each virtual memory segment has its own protection (access rights), which may cause a segmentation violation (SIGSEGV) if the memory is accessed incorrectly (e.g., writing to a read-only segment). Accessing virtual memory outside of the segments will also cause a segmentation violation.

Если mremap() используется для перемещения или расширения области, заблокированной mlock(2) или эквивалентом, то вызов mremap() постарается заполнить новую область, но не завершится с ошибкой ENOMEM, если область невозможно заполнить.

До версии 2.4, в glibc не был определён флаг MREMAP_FIXED, а прототип mremap() не позволял указывать аргумент new_address.

MREMAP_DONTUNMAP use cases

Possible applications for MREMAP_DONTUNMAP include:

  • Non-cooperative userfaultfd(2): an application can yank out a virtual address range using MREMAP_DONTUNMAP and then employ a userfaultfd(2) handler to handle the page faults that subsequently occur as other threads in the process touch pages in the yanked range.
  • Garbage collection: MREMAP_DONTUNMAP can be used in conjunction with userfaultfd(2) to implement garbage collection algorithms (e.g., in a Java virtual machine). Such an implementation can be cheaper (and simpler) than conventional garbage collection techniques that involve marking pages with protection PROT_NONE in conjunction with the of a SIGSEGV handler to catch accesses to those pages.

ДЕФЕКТЫ

До Linux 4.14, если old_size равно нулю и отображение, на которое указывает old_address — частное отображение (mmap(2) MAP_PRIVATE), то вызов mremap() создавал новое частное отображение, не относящееся к первоначальному отображению. Такое поведение не предусматривалось и, вероятно, не ожидается в приложениях пользовательского пространства (так предназначение mremap() — создание нового отображения на основе первоначального). Начиная с Linux 4.14, в этом случае mremap() завершается ошибкой EINVAL.

СМ. ТАКЖЕ

brk(2), getpagesize(2), getrlimit(2), mlock(2), mmap(2), sbrk(2), malloc(3), realloc(3)

Описание страничной памяти в вашей любимой книге по операционным системам (например, Современные операционные системы Эндрю С. Таненбаума, Внутри Linux Рэндольфа Бентсона, Архитектура операционной системы UNIX Мориса Дж. Баха)

ЗАМЕЧАНИЯ

Эта страница является частью проекта Linux man-pages версии 5.10. Описание проекта, информацию об ошибках и последнюю версию этой страницы можно найти по адресу https://www.kernel.org/doc/man-pages/.

ПЕРЕВОД

Русский перевод этой страницы руководства был сделан aereiae <aereiae@gmail.com>, Alexey <a.chepugov@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, ITriskTI <ITriskTI@gmail.com>, Max Is <ismax799@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Малянов Евгений Викторович <maljanow@outlook.com>

Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.

9 июня 2020 г. Linux