为什么在POSIX中创建消息队列时出现"无法分配内存"的错误?

ero*_*gol 4 c linux posix ipc message-queue

为什么在POSIX中创建消息队列时出现"无法分配内存"的错误?

Art*_*ken 6

Adrian的回答是正确的,但是因为这是一个令人沮丧的常见错误,当第一次尝试使用POSIX消息队列进行任何非平凡的事情时遇到Linux,我想我会添加一些有用的细节.

首先,要了解RLIMIT_MSGQUEUE资源限制,请参阅以下公式man setrlimit:

RLIMIT_MSGQUEUE(自Linux 2.6.8起)指定可为POSIX消息队列分配的调用进程的实际用户ID的字节数限制.对mq_open(3)强制执行此限制.根据以下公式,用户创建的每个消息队列都会根据此限制计数(直到删除):

bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) +
        attr.mq_maxmsg * attr.mq_msgsize
Run Code Online (Sandbox Code Playgroud)

其中attr是指定为mq_open(3)的第四个参数的mq_attr结构.公式中的第一个加数,包括sizeof(struct msg_msg*)(Linux/i386上的4个字节),确保用户无法创建无限数量的零长度消息(但这些消息每个消耗一些系统内存用于簿记开销).

鉴于Linux上的默认MQ设置(mq_maxmsg= 10,mq_msgsize= 8192),上述公式仅适用于大约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
Run Code Online (Sandbox Code Playgroud)

如果您还确保在打开队列时将mq_maxmsgmq_msgsize属性设置为较低的值(请参阅参考资料man mq_open),即使在默认RLIMIT_MSGQUEUE硬限制的约束内,您也可以使用几百个队列.当然,具体取决于您的特定用例.

RLIMIT_MSGQUEUE如果您具有对系统的root访问权限,则调整硬限制并不困难.一旦你弄清楚应该是什么限制,请调整系统范围的设置/etc/security/limits.conf.例如,要为www-data用户组设置4 MB的硬限制和软限制,并且对超级用户没有限制,您需要在文件中添加以下行:

@www-data   -   msgqueue    4194304
root        -   msgqueue    unlimited
Run Code Online (Sandbox Code Playgroud)


Adr*_*Cox 5

最可能的原因是您要求的消息队列大于允许的空间.系统限制受控制/proc/sys/fs/mqueue/.还有一个每用户限制(RLIMIT_MSGQUEUE),它控制单个用户可以分配的总字节数.要检查系统上的设置,请查看值ulimit -q,默认值为819200字节.

开发人员认为消息队列适用于小型,低延迟的消息.分发使用较大消息队列的应用程序很困难,因为需要进行系统管理更改才能解除限制.