我的程序在C中,我正在用gcc编译。我正在读取文件,并将文件的内容存储到缓冲区中。为此,我需要缓冲区与文件一样大。我正在使用malloc()为缓冲区分配内存。不幸的是,我遇到了一个277MB的文件。这对堆来说太过分了吗?我在运行时遇到了一个seg错误,但没有更多的信息。它适用于大小为160 MB的文件,但这个277MB文件的单个异常值正在破坏它。
编辑:valgrind给了我@ 0xC0000022L valgrind给了我
==6380== Warning: set address range perms: large range [0x8851028, 0x190e6102) (undefined)
==6380== Warning: set address range perms: large range [0x8851028, 0x190e6028) (defined)
==6380== Warning: set address range perms: large range [0x190e7028, 0x2997c108) (undefined)
==6380== Warning: set address range perms: large range [0x190e7028, 0x2997c028) (defined)
==6380== Warning: silly arg (-1737565464) to malloc()
==6380== Invalid write of size 4
==6380== at 0x8048A49: main (newanalyze.c:85)
==6380== Address 0x4a00 is not stack'd, malloc'd or (recently) free'd
==6380==
==6380==
==6380== Process terminating with default action of signal 11 (SIGSEGV)
==6380== Access not within mapped region at address 0x4A00
==6380== at 0x8048A49: main (newanalyze.c:85)
但第85行只是一个不应受文件大小影响的小变量。
答案 0 :(得分:3)
请注意Valgrind的输出,
== 6380 ==警告:愚蠢的arg(-1737565464)到malloc()
-1737565464是带符号的int值,如果它被视为unsigned int,则为2557401832(> 2G)。您将> 2G参数传递给malloc而不是277M。
根据以下信息,我们知道您正在尝试写入地址0x4a00这是一个无效的地址,在这种情况下您会期望SEGV。请检查代码中的newanalyze.c:85,看看它是什么。
== 6380 ==写入大小4无效
== 6380 ==在0x8048A49:main(newanalyze.c:85)
== 6380 ==地址0x4a00没有堆叠,malloc'd或(最近)免费
答案 1 :(得分:1)
跟进其中一条评论,以下是使用mmap(2)打开文件的方法。这假设您使用的是unix。
int fd;
struct stat S;
const char* file_base;
if ((fd = open(filename, O_RDONLY)) < 0) {
fprintf(stderr, "Can't open file %s to read\n", filename);
return NULL;
}
if (fstat(fd, &S) != 0) {
fprintf(stderr, "Can't stat file %s!\n", filename);
close(fd);
return NULL;
}
if ((file_base = mmap(NULL, S.st_size, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
fprintf(stderr, "Unable to map file %s\n", filename);
close(fd);
return NULL;
}
在此之后,file_base
指向一个包含文件全部内容的内存。
这种方式的优点是:
这有一点内存标记为只读;您也可以使用文件读写来执行此操作,但这意味着如果您写入内存,则会同时更改文件。
如果您不在unix上,可能仍然可以使用mmap
功能。如果没有,那么将会有一些Windows本地方式做同样的事情(CreateFileMapping
)。
答案 2 :(得分:0)
不幸的是,我不能给你一个坚实的“为什么”,但mmap2,它是malloc在你的系统上调用的东西,只是报告它的内存不足。在这种情况下,Malloc将返回NULL导致段错误。
munmap(0xb7706000, 4096) = 0
mmap2(NULL, 2557403136, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
作为一个反例,我有一个成功的玩具程序:
mmap(NULL, 283652096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2d00994000
我会检查系统上可用的内存或程序正在使用的内存。也许这会严重泄漏记忆?