Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there a error "Cannot Allocate Memory" while creating message queue in POSIX?

Why is there a error "Cannot Allocate Memory" while creating message queue in POSIX?

like image 237
erogol Avatar asked Dec 17 '22 16:12

erogol


1 Answers

Adrian's answer is correct, but since this is a frustratingly common error to run into on Linux when first attempting to use POSIX message queues for anything non-trivial, I thought I'd add some helpful particulars.

First, to understand the RLIMIT_MSGQUEUE resource limit, see the formula at man setrlimit:

RLIMIT_MSGQUEUE (Since Linux 2.6.8) Specifies the limit on the number of bytes that can be allocated for POSIX message queues for the real user ID of the calling process. This limit is enforced for mq_open(3). Each message queue that the user creates counts (until it is removed) against this limit according to the formula:

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

where attr is the mq_attr structure specified as the fourth argument to mq_open(3). The first addend in the formula, which includes sizeof(struct msg_msg *) (4 bytes on Linux/i386), ensures that the user cannot create an unlimited number of zero-length messages (such messages nevertheless each consume some system memory for bookkeeping overhead).

Given the default MQ settings (mq_maxmsg = 10, mq_msgsize = 8192) on Linux, the above formula works out to only about 10 message queues for the default limit of 819200 bytes. Hence why you will run into this problem as soon as you e.g. forget to close and unlink a couple of queues once done with them.

To raise the RLIMIT_MSGQUEUE resource limit to the maximum allowed for the user, you can use something like the following in your application's startup code:

#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

If you also ensure that you set the mq_maxmsg and mq_msgsize attributes to lower values when opening a queue (see man mq_open), you may be able to get away with a couple of hundred queues even within the constraints of the default RLIMIT_MSGQUEUE hard limit. Depending on your particular use case, of course.

Adjusting the RLIMIT_MSGQUEUE hard limit is not difficult if you have root access to the system. Once you've figured out what the limit ought to be, adjust the system-wide settings in /etc/security/limits.conf. For example, to set a hard and soft limit of 4 megabytes for the www-data user group, and no limitation for the superuser, you'd add the following lines to the file:

@www-data   -   msgqueue    4194304
root        -   msgqueue    unlimited
like image 176
Arto Bendiken Avatar answered Jan 14 '23 15:01

Arto Bendiken