Запрет очевидного перерасхода означает, что можно создавать отображения, размер которых не превышает объем свободной памяти, доступной в текущий момент времени. Это ограничение не будет распространяться на уже существующие отображения (поскольку они могут не задействовать все отображенные ими страницы).
Начиная с версии 2.6, вместо положительных значений применяется 1, а значение 2 (или больше) приводит к использованию политики
[размер файла подкачки] + [размер физической памяти] * overcommit_ratio / 100
Значение overcommit_ratio представляет собой целое процентное значение и хранится в файле /proc/sys/vm/overcommit_ratio (доступном только в Linux). По умолчанию оно равно 50; это значит, что при выделении адресного пространства ядро может успешно превысить размер доступной в системе памяти на 50 % (если только все процессы не попытаются одновременно использовать всю выделенную им память).
Стоит отметить, что мониторинг перерасхода памяти касается только следующих типов отображения:
• приватные отображения, доступные для записи (как файловые, так и анонимные), выделяемые отдельно для каждого процесса, который их задействует;
• разделяемые анонимные отображения, существующие в единственном экземпляре (поскольку они разделяются всеми процессами).
В резервировании пространства подкачки для приватного отображения, доступного только для чтения, нет необходимости: поскольку содержимое отображения не может быть изменено, не нужно использовать это пространство. Оно также не требуется для разделяемых файловых отображений, так как отображенный файл сам играет роль файла подкачки.
При вызове fork() дочерний процесс наследует не только отображение, но и его параметр MAP_NORESERVE. Этот флаг не предусмотрен стандартом SUSv3, но поддерживается в нескольких реализациях UNIX, включая Linux.
В данном разделе мы рассмотрели ситуации, в которых вызов mmap() может не суметь увеличить адресное пространство процесса ввиду системных ограничений, касающихся физической памяти и пространства подкачки. Причиной также может оказаться ограничение на ресурсы RLIMIT_AS (описанное в разделе 36.3), ограничивающее максимальный размер адресного пространства, выделяемый для вызывающего процесса.
Выше упоминалось, что при использовании отложенного резервирования память может быть исчерпана, если приложения попытаются получить доступ ко всему диапазону своих отображений. В таком случае для освобождения памяти ядро прибегает к принудительному завершению процессов.
Подсистема ядра, предназначенная для выбора процессов, которые следует завершить при нехватке памяти, известна под названием OOM killer (OOM от англ. out-of-memory — «нехватка памяти»). Данный механизм пытается выбрать наиболее подходящие для завершения процессы; критерии, учитываемые им при этом, зависят от целого ряда факторов. Например, чем больше памяти потребляет процесс, тем выше вероятность того, что OOM killer выберет именно его. Среди других факторов, принимаемых во внимание, можно отметить низкое значение nice (то есть больше 0) и попытки создания множества дочерних процессов. Ядро предпочитает не трогать следующие процессы:
• привилегированные процессы, поскольку они, вероятно, выполняют важные задачи;
• процессы, напрямую работающие с устройствами, так как их принудительное завершение может оставить устройство в нерабочем состоянии;
• процессы, которые работают продолжительное время или потребили значительный объем ресурсов процессора, так как их принудительное завершение может означать, что вся их работа была проделана впустую.
Для принудительного завершения процесса OOM killer отправляет ему сигнал SIGKILL.
В Linux с версии 2.6.11 существует файл /proc/PID/oom_score; в нем хранится «вес», который ядро назначает процессу, когда возникает необходимость в вызове OOM killer. Чем больше данное значение, тем выше вероятность того, что процесс при необходимости будет выбран для принудительного завершения. В версии ядра 2.6.11 также появился файл /proc/PID/oom_adj, с помощью которого можно повлиять на значение oom_score процесса. Этому файлу можно назначить любое число в диапазоне от –16 до +15; отрицательные значения снижают oom_score, а положительные — повышают. Если указать специальное значение -17, процесс перестанет рассматриваться системой OOM killer как кандидат на завершение. Дальнейшие подробности можно найти на странице proc(5) руководства.
Если указать в аргументе flags вызова mmap() флаг MAP_FIXED, ядро будет интерпретировать адрес, заданный в аргументе addr, буквально, а не как точку отсчета. В таком случае адрес должен быть изначально выровнен по странице.