6

我是 64 位架构的新手。你能告诉我 64 位 linux 机器中文件映射支持的最大文件大小是多少。我想通过文件映射打开超过20GB的文件,可以吗?

我写了一个示例代码。但是当我在 GBSIZE 偏移量中获取指针的值时,它会导致总线错误:

unsigned char* pCur = pBegin + GBSIZE;
//pBegin is the pointer returned by mmap
printf("%c",*pCur); 

顺便说一句,printf("%c",*pBegin );工作正常。和我的地址大小:38 位物理,48 位虚拟

这是完整的代码:

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

//#define FILEPATH "smallfile"
#define FILEPATH "bigfile"
#define GBSIZE (1024L*1024L*1024L)
#define TBSIZE (1024L*GBSIZE)
#define NUMSIZE  (20L * GBSIZE)
//#define NUMSIZE  (10)
#define FILESIZE (NUMINTS * sizeof(int))

int main(int argc, char *argv[])
{
    int i;
    int fd;
    unsigned char *pBegin;

    fd = open(FILEPATH, O_RDONLY);
        if (fd == -1) {
        perror("Error opening file for reading");
        exit(EXIT_FAILURE);
    }

    pBegin = mmap(0, NUMSIZE, PROT_READ, MAP_SHARED, fd, 0);
    if (pBegin == MAP_FAILED) {
        close(fd);
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }

    /** ERROR happens here!!! **/
    unsigned char* pCur = pBegin + GBSIZE;
    printf("%c",*pCur);

    if (munmap(pBegin, NUMSIZE) == -1) {
        perror("Error un-mmapping the file");
    }
    close(fd);
    return 0;
}
4

5 回答 5

12

尽管指针是 64 位宽的,但大多数处理器实际上并不支持使用完整 64 位的虚拟地址。要查看您的处理器支持的虚拟地址大小,请查看/proc/cpuinfo(通常为 48 位)。

grep "address sizes" /proc/cpuinfo

此外,内核使用了一半的虚拟地址空间,而对用户空间不可用——在当前的 Linux 实现中剩下 47 位。

但是,即使考虑到这一点,您仍然有足够的空间容纳 20GB 的文件。47位理论上意味着128TB的虚拟地址空间。

于 2010-01-29T02:54:53.873 回答
5

mmap(2)手册页:

   void *mmap(void *addr, size_t length, int prot, int flags,
              int fd, off_t offset);

length是 a size_t,在 64 位机器上的长度为 64 位。因此是的,理论上你可以映射一个 20GB 的文件。

于 2010-01-29T02:21:08.570 回答
1

(此答案最初由 OP 编辑​​成问题)

您已请求将 20GB 映射到一个只有 50MB 大小的文件上。

mmap 手册页所述,mmap当您请求长度太大时会成功,但是它会给出SIGBUSSIGSEGV当您实际尝试读取超出基础文件的末尾时。

于 2014-12-25T21:23:24.103 回答
1

64 位地址允许超过 20 GB 的多个数量级。

于 2010-01-29T02:19:30.350 回答
0

同意 MarkR,您取消引用无效地址。

// A bug in these lines.
unsigned char* pCur = pBegin + GBSIZE;      
printf("%c",*pCur);  

unsigned char* pEnd = pBegin + NUMSIZE;  
unsigned char* pLast = pEnd - 1;
unsigned char* pCur = pLast;

我修改了您的代码以使用 HUGE TLB 标志,如下所示。

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

#define MAP_HUGETLB     0x40000         /*  create a huge page mapping */
#define MAP_HUGE_SHIFT  26
#define MAP_HUGE_1GB    (30 << MAP_HUGE_SHIFT)

#define KSIZE 1024L
#define MSIZE (1024L*1024L)
#define GSIZE (1024L*1024L*1024L)
#define TSIZE (1024L*GSIZE)

#define INIT_MEM 0
// Fail on my MacBook Pro (Retina, 13-inch, Early 2015)
// Darwin Kernel Version 16.5.0:x86_64
// #define NUMSIZE  (16L * TSIZE)

// mmap ok; init: got killed; signal 9
// #define NUMSIZE  (8L * TSIZE)

// Got killed signal 9
// #define NUMSIZE  (1L * TSIZE)

// OK
// #define NUMSIZE  (200L * GSIZE)

// OK
#define NUMSIZE  (20L * GSIZE)
typedef unsigned long long ETYPE;

#define MEMSIZE (NUMSIZE*sizeof(ETYPE))
#define PGSIZE (16*KSIZE)

void init(ETYPE* ptr) {
        *ptr = (ETYPE)ptr;
}

int verify(ETYPE* ptr) {
        if (*ptr != (ETYPE)ptr) {
                fprintf(stderr, "ERROR: 0x%016llx != %p.\n", *ptr, ptr);
                return -1;
        }
        else {
                fprintf(stdout, "OK: 0x%016llx = %p.\n", *ptr, ptr);
        }
        return 0;
}
int main(int argc, char *argv[])
{
    int i;
    int fd;
    ETYPE *pBegin;

    int flags = MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_HUGE_1GB;
    printf("mmap memory size:%lu GB\n", MEMSIZE/GSIZE);
    pBegin = (ETYPE*) mmap(0, MEMSIZE, PROT_READ | PROT_WRITE, flags, -1, 0);
    if (pBegin == MAP_FAILED) {
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }

    ETYPE* pEnd = pBegin + NUMSIZE;
    ETYPE* pCur = pBegin;

#if INIT_MEM
    while (pCur < pEnd) {
            init(pCur);
            // ++pCur;  //slow if init all addresses.
            pCur += (PGSIZE/sizeof(ETYPE)); 
    }
#endif

    init(&pBegin[0]);
    init(&pBegin[NUMSIZE-1]);

    verify(&pBegin[0]);
    verify(&pBegin[NUMSIZE-1]);

    if (munmap(pBegin, MEMSIZE) == -1) {
        perror("Error un-mmapping the file");
    }
    return 0;
}
于 2017-06-16T06:53:21.100 回答