我是64位架构的新手。你能告诉我64位linux机器中文件映射支持的MAX文件大小吗?我想通过文件映射打开超过20GB的文件,是否可用?
我写了一个示例代码。但是当我在GBSIZE偏移量中得到指针的值时,它会导致总线错误:
unsigned char* pCur = pBegin + GBSIZE;
//pBegin is the pointer returned by mmap
printf("%c",*pCur);
BTW,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;
}
答案 0 :(得分:9)
虽然指针是64位宽,但大多数处理器实际上并不使用完整的64位来支持虚拟地址。要查看处理器支持的虚拟地址大小,请查看/proc/cpuinfo
(通常为48位)。
grep "address sizes" /proc/cpuinfo
此外,一半的虚拟地址空间由内核使用,不可供用户空间使用 - 在当前的Linux实现中留下47位。
然而,即使考虑到这一点,你仍然会有足够的空间来容纳20GB的文件。理论上47位意味着128TB的虚拟地址空间。
答案 1 :(得分:5)
来自mmap(2)
手册页:
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
length
是size_t
,在64位计算机上长度为64位。因此,是的,理论上你可以映射一个20GB的文件。
答案 2 :(得分:1)
64位地址允许超过20 GB的许多数量级。
答案 3 :(得分:1)
(这个答案最初是由OP编写的问题)
您已经请求将20GB的地图放到一个只有50MB大小的文件上。
正如the mmap man page所述,mmap
在请求长度过大时会成功,但是当您实际尝试阅读超出结束时,它会给SIGBUS
或SIGSEGV
底层文件。
答案 4 :(得分: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;
我修改了你的代码以使用巨大的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;
}