为什么在POSIX中创建消息队列时出现“无法分配内存”的错误?
答案 0 :(得分: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
其中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
如果您还确保在打开队列时将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
答案 1 :(得分:5)
最可能的原因是您要求的邮件队列大于允许的空间。系统限制在/proc/sys/fs/mqueue/
中控制。还有每用户限制(RLIMIT_MSGQUEUE
),它控制单个用户可以分配的总字节数。要检查系统上的设置,请查看ulimit -q
的值,默认值为819200字节。
开发人员认为消息队列适用于小型,低延迟的消息。分发使用较大消息队列的应用程序很困难,因为需要进行系统管理更改才能解除限制。