在x86_64架构下,Linux共享内存分配

6

我有一台64位的REHL Linux机器,
Linux ipms-sol1 2.6.32-71.el6.x86_64 #1 SMP x86_64 x86_64 x86_64 GNU/Linux

内存大小为约38GB。

我在/etc/sysctl.conf中更改了默认的共享内存限制,并将更改后的文件加载到内存中作为sysctl -p。

kernel.shmmni=81474836
kernel.shmmax=32212254720
kernel.shmall=7864320

仅出于实验目的,我将shmmax大小改为32GB,并尝试使用shmget()在代码中分配10GB共享内存,但无法一次性获得10GB的共享内存。当我将共享空间需求降低到8GB时,它成功了。请问我可能做错了什么?

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

#define SHMSZ 10737418240

main()
{
    char c;
    int shmspaceid;
    key_t key;
    char *shm, *s;
    struct shmid_ds shmid;

    key = 5678;
    fprintf(stderr,"Changed code\n");

    if ((shmspaceid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
        fprintf(stderr,"ERROR memory allocation failed\n");
        return 1;
    }


    shmctl(shmspaceid, IPC_RMID, &shmid);
    return 0;
}

敬礼, Himanshu


你的shmall大小似乎假定getconf PAGE_SIZE为4096。你确认过了吗? - antiduh
Ping。你解决了这个问题吗?我很好奇答案是什么,因为这是其他人和我在自己的项目中可能会遇到的问题。 - antiduh
3个回答

1

我不确定这个解决方案是否同样适用于共享内存,但我知道这种现象来自普通的malloc()调用。

很常见的情况是,你不能像在这里尝试的那样分配非常大的内存块。函数调用的意思是“为我分配一个连续的10737418240字节的内存块”。通常情况下,即使总系统内存理论上可以满足这个需求,隐含的“一个连续的内存块”会导致可分配内存的限制要低得多。

内存中的程序结构、加载的程序数量都可能会阻塞某些内存区域,不允许有10个连续的Gigabyte的可分配内存。

我经常发现重新启动计算机会改变这种情况(因为程序被加载到堆的不同位置)。你可以用类似这样的方式尝试一下你的最大可分配块大小:

int i=1024;
int error=0;
while(!error) {
  char *a=(char*)malloc(i);
  error=(a==null);
  if(!error)
    printf("Successfully allocated %i.\n", i);
  i*=2;
}

希望这对你有所帮助或适用。我在检查为什么无法将接近最大系统内存分配给JVM时发现了这一点。

2
它不必是10GB的连续RAM。它只需要是虚拟连续的,并且在64位虚拟空间中应该有足够的空间来找到一个10GB的块。 - Zan Lynx
以上我只是写了一个样例程序来找出问题,真正需要连续共享内存的原因是数据库配置要求大规模内存数据库具有至少10GB的连续共享内存,否则它无法正常运行。但无论如何,感谢您的评论,至少我知道需要去哪里寻找答案了。 - userindia
那么这就是你的问题了吗?接受我的解决方案怎么样? :) - 0xCAFEBABE
1
嘿,0xCAFEBABE,你的解决方案不适用。 - userindia

1
在黑暗中射击:您没有足够的交换空间。默认情况下,共享内存需要在交换空间中保留空间。您可以使用SHM_NORESERVE禁用此行为。

http://linux.die.net/man/2/shmget

SHM_NORESERVE (自 Linux 2.6.15 起) 该标志与 mmap(2) 中的 MAP_NORESERVE 标志具有相同的目的。不为此段保留交换空间。当保留交换空间时,可以保证可以修改该段。如果没有保留交换空间,当没有可用的物理内存时,写操作可能会导致 SIGSEGV。另请参见 proc(5) 中有关文件 /proc/sys/vm/overcommit_memory 的讨论。


0
我刚刚看了一下这个问题,我建议打印出确切的errno值和问题描述,而不仅仅是指出它失败了。例如:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

//#define SHMSZ 10737418240
#define SHMSZ 8589934592

int main()
{
    int shmspaceid;
    key_t key = 5678;
    struct shmid_ds shmid;

    if ((shmspaceid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
        fprintf(stderr,"ERROR with shmget (%d: %s)\n", (int)(errno), strerror(errno));
        return 1;
    }

    shmctl(shmspaceid, IPC_RMID, &shmid);
    return 0;
}

我尝试在我的16 GB系统上使用8 GB块和8 GB smhmax和shmall来复现您的问题,但是我无法做到。它正常工作。我建议使用ipcs -m查找其他共享块,这些块可能会阻止您的10 GB分配得到认可。并且一定要仔细查看shmget()通过errno返回的确切错误代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接