Почему при создании очереди сообщений в POSIX возникает ошибка «Не удается выделить память»? - PullRequest
4 голосов
/ 12 марта 2011

Почему при создании очереди сообщений в POSIX возникает ошибка «Не удается выделить память»?

Ответы [ 2 ]

6 голосов
/ 03 августа 2011

Ответ Адриана верен, но, поскольку это ошибочно встречающаяся ошибка, с которой приходится сталкиваться в Linux при первой попытке использовать очереди сообщений POSIX для чего-то нетривиального, я решил добавить некоторые полезные сведения.

Во-первых, чтобы понять ограничение ресурса RLIMIT_MSGQUEUE, см. Формулу в man setrlimit:

RLIMIT_MSGQUEUE (начиная с Linux 2.6.8) Указывает ограничение на количество байтов, которые могут быть выделены для очередей сообщений POSIX для реального идентификатора пользователя вызывающего процесса. Это ограничение применяется для mq_open (3). Каждая очередь сообщений, которую создает пользователь, учитывает (до тех пор, пока она не будет удалена) этот предел согласно формуле:

bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) +
        attr.mq_maxmsg * attr.mq_msgsize

где attr - структура mq_attr, указанная в качестве четвертого аргумента для mq_open (3). Первое дополнение в формуле, которое включает sizeof (struct msg_msg *) (4 байта в Linux / i386), гарантирует, что пользователь не может создавать неограниченное количество сообщений нулевой длины (такие сообщения, тем не менее, каждый из них использует некоторую системную память для накладных расходов на ведение бухгалтерского учета ).

Учитывая настройки MQ по умолчанию (mq_maxmsg = 10, mq_msgsize = 8192) в Linux, приведенная выше формула работает только с 10 очередями сообщений для ограничения по умолчанию в 819200 байт. Следовательно, почему вы столкнетесь с этой проблемой, как только вы, например, забудьте закрыть и отсоединить пару очередей, однажды сделанных с ними.

Чтобы поднять ограничение ресурса RLIMIT_MSGQUEUE до максимально допустимого для пользователя, вы можете использовать что-то вроде следующего в коде запуска вашего приложения:

#ifdef __linux__
    // Attempt to raise the resource limits for POSIX message queues to
    // the current hard limit enforced for the current real user ID:
    struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY};
    const int rc = getrlimit(RLIMIT_MSGQUEUE, &rlim);
    if (rc == 0 && rlim.rlim_cur != rlim.rlim_max) {
      rlim.rlim_cur = rlim.rlim_max;
      setrlimit(RLIMIT_MSGQUEUE, &rlim);
    }
#endif

Если вы также убедитесь, что для атрибутов mq_maxmsg и mq_msgsize установлены более низкие значения при открытии очереди (см. man mq_open), вы можете избежать нескольких сотен очередей даже в рамках ограничений. по умолчанию RLIMIT_MSGQUEUE жесткий предел. Конечно, в зависимости от вашего конкретного случая использования.

Настройка жесткого ограничения RLIMIT_MSGQUEUE не составляет труда, если у вас есть root-доступ к системе. Как только вы выяснили, каким должен быть предел, настройте общесистемные настройки в /etc/security/limits.conf. Например, чтобы установить жесткий и мягкий лимит в 4 мегабайта для группы пользователей www-data, а для суперпользователя ограничений нет, добавьте в файл следующие строки:

@www-data   -   msgqueue    4194304
root        -   msgqueue    unlimited
5 голосов
/ 13 марта 2011

Наиболее вероятной причиной является то, что вы запросили очередь сообщений, размер которой превышает допустимое пространство.Пределы системы контролируются в /proc/sys/fs/mqueue/.Существует также ограничение на пользователя (RLIMIT_MSGQUEUE), которое контролирует общее количество байтов, которое может выделить один пользователь.Чтобы проверить настройки в вашей системе, посмотрите на значение ulimit -q, которое по умолчанию составляет 819200 байт.

Разработчики считают, что очереди сообщений подходят для небольших сообщений с низкой задержкой.Трудно распространять приложение, использующее большие очереди сообщений, поскольку для снятия ограничений требуются изменения в системном администрировании.

...