【发布时间】:2011-07-14 04:40:23
【问题描述】:
为什么在 POSIX 中创建消息队列时出现“无法分配内存”错误?
【问题讨论】:
-
您使用什么代码来尝试创建它?
-
猜想,但是当您创建消息队列时,您的系统可能无法分配足够的内存(也许您在创建队列时传递了一些错误的参数,请显示该代码)
标签: c linux posix ipc message-queue
为什么在 POSIX 中创建消息队列时出现“无法分配内存”错误?
【问题讨论】:
标签: c linux posix ipc message-queue
Adrian 的回答是正确的,但由于这是在 Linux 上首次尝试将 POSIX 消息队列用于任何重要的事情时遇到的一个令人沮丧的常见错误,我想我会添加一些有用的细节。
首先要了解RLIMIT_MSGQUEUE的资源限制,见man setrlimit处的公式:
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
其中 attr 是指定为 mq_open(3) 的第四个参数的 mq_attr 结构。 公式中的第一个加数包括 sizeof(struct msg_msg *)(在 Linux/i386 上为 4 个字节),确保用户不能创建无限数量的零长度消息(尽管这样的消息每个都消耗一些系统内存来记账开销)。
鉴于 Linux 上的默认 MQ 设置(mq_maxmsg = 10、mq_msgsize = 8192),对于 819200 字节的默认限制,上述公式仅适用于大约 10 个消息队列。因此,为什么你会遇到这个问题,例如完成后忘记关闭和取消链接几个队列。
要将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 硬限制。当然,这取决于您的特定用例。
如果您对系统具有 root 访问权限,则调整 RLIMIT_MSGQUEUE 硬限制并不困难。一旦你弄清楚了应该是什么限制,在/etc/security/limits.conf 中调整系统范围的设置。例如,要为 www-data 用户组设置 4 MB 的硬性和软性限制,并且对超级用户没有限制,您可以在文件中添加以下行:
@www-data - msgqueue 4194304
root - msgqueue unlimited
【讨论】:
最可能的原因是您请求的消息队列大于允许的空间。系统限制在/proc/sys/fs/mqueue/ 中控制。还有一个每个用户的限制 (RLIMIT_MSGQUEUE),它控制单个用户可以分配的字节总数。要检查系统上的设置,请查看 ulimit -q 的值,默认为 819200 字节。
开发人员认为消息队列适用于小型、低延迟的消息。分发使用较大消息队列的应用程序很困难,因为需要更改系统管理才能解除限制。
【讨论】: