即使有足够的页面,shmget也会因ENOMEM而失败

时间:2014-02-11 14:53:05

标签: c++ linux memory-management shared-memory huge-pages

当我们尝试从大页面分配大约10MB的内存块时,我们会遇到奇怪的行为。系统是SL6.4 64位,最近的Intel CPU,64GB RAM。

最初我们分配了20个大页面,这应该足够了。

$ cat /proc/meminfo | grep Huge
AnonHugePages:         0 kB
HugePages_Total:      20
HugePages_Free:       20
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

其他大页面设置:

/proc/sys/kernel/shmall = 4294967296
/proc/sys/kernel/shmmax = 68719476736
/proc/sys/kernel/shmmni = 4096
/proc/sys/kernel/shm_rmid_forced = 0
使用ENOMEM

shmget失败。我能找到的唯一解释是在手册页中指出“没有内存可以分配给段开销”。但我无法发现“段开销”是什么。

在配置了相同页数的另一台服务器上shmget成功返回。

在问题服务器上,我们将大页面的数量增加到100.分配成功,但也分配了64个2MB大页面:

$ ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x0091efab 10223638   rsprod     600        2097152    1
0x0092efab 10256407   rsprod     600        2097152    1
0x0093efab 10289176   rsprod     600        2097152    1
0x0094efab 10321945   rsprod     600        2097152    1
0x0095efab 10354714   rsprod     600        2097152    1
0x0096efab 10387483   rsprod     600        2097152    1
...
0x00cdefab 12189778   rsprod     600        2097152    1
0x00ceefab 12222547   rsprod     600        2097152    1
0x00cfefab 12255316   rsprod     600        2097152    1
0x00d0efab 12288085   rsprod     600        2097152    1
0x00000000 12320854   rsprod     600        10485760   1

调用shmget的代码如下。这仅在应用程序中调用一次。     uint64_t GetHugePageSize()     {         FILE * meminfo = fopen(“/ proc / meminfo”,“r”);         if(meminfo == NULL){             返回0;         }

    char line[256];
    while(fgets(line, sizeof(line), meminfo)) {
        uint64_t zHugePageSize = 0;
        if(sscanf(line, "Hugepagesize: %lu kB", &zHugePageSize) == 1) {
            fclose(meminfo);
            return zHugePageSize*1024;
        }
    }

    fclose(meminfo);
    return 0;
}

char* HugeTableNew(size_t aSize, int& aSharedMemID)
{
    static const uint64_t sHugePageSize = GetHugePageSize();

    uint64_t zSize = aSize;
    // round up to next page size, otherwise shmat fails with EINVAL (22)
    const uint64_t HUGE_PAGE_MASK = sHugePageSize-1;
    if(aSize & HUGE_PAGE_MASK) {
        zSize = (aSize&~HUGE_PAGE_MASK) + sHugePageSize;
    }

    aSharedMemID = shmget(IPC_PRIVATE, zSize, IPC_CREAT|SHM_HUGETLB|SHM_R|SHM_W);
    if(aSharedMemID < 0) {
        perror("shmget");
        return nullptr;
    }
...

有谁知道:

  • 当有足够的免费大页面可用时,导致分配失败的原因是什么?
  • 是什么导致分配额外的2MB页面?
  • “分段开销”是什么?

0 个答案:

没有答案