2010-05-26 65 views
10

我一直在使用openSUSE 11.2 x86_64上的大型稀疏文件。當我嘗試mmap()1TB稀疏文件時,它與ENOMEM一起失敗。我本以爲64位地址空間足以映射成TB,但似乎不是。進一步試驗,1GB文件可以正常工作,但2GB文件(以及其他更大的文件)會失敗。我猜測可能有一個設置在某處進行調整,但廣泛的搜索沒有任何結果。爲什麼在1TB稀疏文件上mmap()會失敗並顯示ENOMEM?

下面是一些顯示問題的示例代碼 - 任何線索?

#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/mman.h> 
#include <sys/types.h> 
#include <unistd.h> 

int main(int argc, char *argv[]) { 
    char * filename = argv[1]; 
    int fd; 
    off_t size = 1UL << 40; // 30 == 1GB, 40 == 1TB 

    fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666); 
    ftruncate(fd, size); 
    printf("Created %ld byte sparse file\n", size); 

    char * buffer = (char *)mmap(NULL, (size_t)size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
    if (buffer == MAP_FAILED) { 
     perror("mmap"); 
     exit(1); 
    } 
    printf("Done mmap - returned 0x0%lx\n", (unsigned long)buffer); 

    strcpy(buffer, "cafebabe"); 
    printf("Wrote to start\n"); 

    strcpy(buffer + (size - 9), "deadbeef"); 
    printf("Wrote to end\n"); 

    if (munmap(buffer, (size_t)size) < 0) { 
     perror("munmap"); 
     exit(1); 
    } 
    close(fd); 

    return 0; 
} 
+0

作爲一個興趣點,你的程序對我來說最多可以處理256GB('1 << 38')的大小,而返回EINVAL的任何數據都會更高。這是在RHEL4上(內核2.6.9-42.0.3.ELsmp)。 – caf 2010-05-26 04:39:38

+4

ulimit -a說什麼? – bmargulies 2010-05-26 04:49:13

+0

謝謝,bmargulies - 就是這樣。 ulimit - 報告的虛擬內存爲1804800千字節(略高於1.7GB)。 ulimit -v 1610612736(1.5TB)讓我mmap我的1TB稀疏文件。我會回答我自己的問題,所以我可以'關閉'它... – metadaddy 2010-05-27 05:47:39

回答

12

問題是每個進程的虛擬內存限制僅設置爲1.7GB。 ulimit -v 1610612736設置爲1.5TB,我的mmap()調用成功。謝謝,bmargulies,提示嘗試ulimit -a!

+2

而且,顯然,我可以在/ etc/profile中設置所需的值(可以是'unlimited')以使其持久。 – metadaddy 2010-05-27 06:00:05

2

是否有某種每用戶配額,限制了用戶進程可用的內存量?

+0

是的 - 我試圖嘗試ulimit -a的bmargulies的建議,並指出'虛擬內存'進程限制爲罪魁禍首 - 請參閱下面的答案。 .. – metadaddy 2010-05-27 05:52:24

1

我的猜測是內核難以分配內存,它需要跟上這個內存映射。我不知道如何在Linux內核中保留換出的頁面(並且我假定大部分文件大部分時間都處於換出狀態),但最終可能需要每頁的條目的文件在表中佔用的內存。由於該文件可能被多個進程映射,因此內核必須跟蹤從進程角度來看的映射,映射到另一個角度,該映射將映射到輔助存儲器(幷包括設備和位置的字段)。

這將適合您的可尋址空間,但可能不適合(至少連續)在物理內存中。

如果有人知道更多關於Linux如何做這件事,我會有興趣聽到它。

+4

Linux將不會創建PTE(頁表條目),直到實際觸及這些頁面。創建映射時的所有功能是創建一個單一的VMA(虛擬內存區域)結構,該結構基本上包含來自'mmap()'的信息。 – caf 2010-05-26 04:37:35

+0

@caf:感謝您的信息 – nategoose 2010-05-26 05:28:17