Ограничение ресурсов процесса: rlimit¶
Что такое rlimit¶
rlimit (resource limit) — это механизм ядра для ограничения потребления ресурсов процессом. Каждый ресурс имеет два предела:
- soft limit (
rlim_cur) — текущее действующее ограничение. Процесс может уменьшить или увеличить его самостоятельно (но не выше hard limit). - hard limit (
rlim_max) — абсолютный максимум. Увеличить его может только процесс с привилегиейCAP_SYS_RESOURCE(обычно root).
Значение RLIM_INFINITY означает отсутствие ограничения.
Основные типы лимитов¶
| Константа | Описание |
|---|---|
RLIMIT_CPU |
Максимальное процессорное время (секунды) |
RLIMIT_FSIZE |
Максимальный размер создаваемого файла (байты) |
RLIMIT_DATA |
Максимальный размер сегмента данных (heap) |
RLIMIT_STACK |
Максимальный размер стека |
RLIMIT_CORE |
Максимальный размер core-дампа |
RLIMIT_NOFILE |
Максимальное количество открытых файловых дескрипторов |
RLIMIT_NPROC |
Максимальное количество процессов одного пользователя |
RLIMIT_AS |
Максимальный размер виртуального адресного пространства |
RLIMIT_MEMLOCK |
Максимальный объём памяти, который можно заблокировать в RAM |
Функции getrlimit и setrlimit¶
#include <sys/resource.h>
struct rlimit {
rlim_t rlim_cur; // soft limit
rlim_t rlim_max; // hard limit
};
// Получить текущий лимит на открытые файловые дескрипторы
struct rlimit lim;
getrlimit(RLIMIT_NOFILE, &lim);
printf("Soft: %ld, Hard: %ld\n", (long)lim.rlim_cur, (long)lim.rlim_max);
// Увеличить soft limit
lim.rlim_cur = 4096;
if (setrlimit(RLIMIT_NOFILE, &lim) != 0) {
perror("setrlimit");
}
Из командной строки через ulimit:
ulimit -a # показать все текущие лимиты
ulimit -n # лимит на файловые дескрипторы
ulimit -n 4096 # установить новый лимит (для текущей оболочки)
ulimit -c unlimited # разрешить неограниченные core-дампы
ulimit -t 10 # ограничить CPU-время до 10 секунд
ulimit -v 524288 # ограничить виртуальную память до 512 МБ
Увеличение размера стека¶
По умолчанию стек ограничен (обычно 8 МБ). Если программа использует глубокую рекурсию или большие локальные массивы, лимит можно увеличить до hard limit:
#include <sys/resource.h>
#include <stdio.h>
int main() {
struct rlimit lim;
// Узнать текущие ограничения
getrlimit(RLIMIT_STACK, &lim);
printf("Soft limit: %ld bytes\n", (long)lim.rlim_cur);
printf("Hard limit: %ld bytes\n", (long)lim.rlim_max);
// Запросить 128 МБ (должно быть <= hard limit)
lim.rlim_cur = 128 * 1024 * 1024;
if (setrlimit(RLIMIT_STACK, &lim) == 0) {
printf("Stack size increased to 128 MB\n");
} else {
perror("setrlimit failed");
}
getrlimit(RLIMIT_STACK, &lim);
printf("New soft limit: %ld bytes\n", (long)lim.rlim_cur);
return 0;
}
Ограничение памяти и CPU-времени¶
Ограничение виртуальной памяти¶
#include <sys/resource.h>
struct rlimit lim;
lim.rlim_cur = 100 * 1024 * 1024; // 100 МБ
lim.rlim_max = 100 * 1024 * 1024;
// RLIMIT_AS — всё виртуальное адресное пространство
setrlimit(RLIMIT_AS, &lim);
Ограничение CPU-времени¶
#include <sys/resource.h>
struct rlimit lim;
lim.rlim_cur = 10; // 10 секунд CPU-времени (soft)
lim.rlim_max = 15; // 15 секунд (hard)
setrlimit(RLIMIT_CPU, &lim);
Что происходит при превышении лимита¶
| Лимит | Последствие превышения |
|---|---|
RLIMIT_CPU (soft) |
Процесс получает SIGXCPU |
RLIMIT_CPU (hard) |
Процесс получает SIGKILL |
RLIMIT_FSIZE |
При записи в файл — SIGXFSZ; write() возвращает EFBIG |
RLIMIT_STACK |
SIGSEGV (stack overflow) |
RLIMIT_DATA / RLIMIT_AS |
brk() / mmap() / malloc() возвращают ошибку (ENOMEM) |
RLIMIT_NOFILE |
open() / socket() возвращают EMFILE |
RLIMIT_NPROC |
fork() возвращает EAGAIN |
RLIMIT_CORE |
Core-дамп будет обрезан или не создан |
Пример проверки превышения CPU-лимита из командной строки:
ulimit -t 5
# Запустить бесконечный цикл:
while true; do :; done
# Через 5 секунд CPU-времени процесс получит SIGXCPU и завершится
prlimit: rlimit для другого процесса¶
prlimit(2) — более гибкая версия setrlimit, позволяющая читать и устанавливать лимиты для любого процесса по
PID (при наличии прав):
#include <sys/resource.h>
struct rlimit lim;
// Получить лимит для процесса с PID pid (0 = текущий процесс)
prlimit(pid, RLIMIT_NOFILE, NULL, &lim);
// Установить лимит для другого процесса
lim.rlim_cur = 1024;
prlimit(pid, RLIMIT_NOFILE, &lim, NULL);
Из командной строки: prlimit --nofile=1024 --pid <pid>
Связанные темы¶
- seccomp — дополнительный механизм изоляции: фильтрация системных вызовов
- fork и exec — лимиты наследуются дочерними процессами через fork; fork-бомба как пример исчерпания
RLIMIT_NPROC - Сигналы —
SIGXCPUиSIGXFSZкак реакция на превышение лимитов
Источники¶
man 2 getrlimit— getrlimit, setrlimit, prlimitman 1 ulimit— управление лимитами из оболочкиman 7 signal— список сигналов (SIGXCPU, SIGXFSZ)man 5 limits.conf— конфигурация системных лимитов через PAM