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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5285101/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:14:43  来源:igfitidea点击:

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

clinuxposixipcmessage-queue

提问by erogol

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

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

采纳答案by Arto Bendiken

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.

Adrian 的回答是正确的,但是由于这是首次尝试将 POSIX 消息队列用于任何重要的事情时在 Linux 上遇到的令人沮丧的常见错误,我想我会添加一些有用的细节。

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

首先,要了解RLIMIT_MSGQUEUE资源限制,请参阅以下公式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:

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

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).

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

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.

鉴于Linux 上的默认 MQ 设置 ( mq_maxmsg= 10, mq_msgsize= 8192),对于 819200 字节的默认限制,上述公式仅适用于大约 10 个消息队列。因此,为什么您会在例如忘记关闭和取消链接几个队列后立即遇到这个问题。

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

要将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

If you also ensure that you set the mq_maxmsgand mq_msgsizeattributes 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_MSGQUEUEhard limit. Depending on your particular use case, of course.

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

Adjusting the RLIMIT_MSGQUEUEhard 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-datauser group, and no limitation for the superuser, you'd add the following lines to the file:

RLIMIT_MSGQUEUE如果您对系统具有 root 访问权限,则调整硬限制并不困难。一旦您确定了限制应该是什么,请在/etc/security/limits.conf. 例如,要为www-data用户组设置 4 兆字节的硬和软限制,而对超级用户没有限制,您需要在文件中添加以下几行:

@www-data   -   msgqueue    4194304
root        -   msgqueue    unlimited

回答by Adrian Cox

The most likely cause is that you've asked for a message queue bigger than the allowed space. The system limits are controlled in /proc/sys/fs/mqueue/. There is also a per user limit (RLIMIT_MSGQUEUE) which controls the total number of bytes that a single user can allocate. To check settings on your system, look at the value of ulimit -q, which defaults to 819200 bytes.

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

The developers consider message queues as suitable for small, low-latency messages. It's difficult to distribute an application that uses larger message queues, as system administration changes are required to lift the limits.

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