堆的大小有多大

时间:2012-07-12 14:14:56

标签: c memory heap

我的程序在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行只是一个不应受文件大小影响的小变量。

3 个答案:

答案 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指向一个包含文件全部内容的内存。

这种方式的优点是:

  • 它基本上没有内存(排序)。这里实际发生的是你将文件作为一些内存的交换空间。
  • 没时间(排序)。新识别的内存开始被换出,因此当访问内存时,所有必须发生的事情就是交换文件的位,这与动态分配{{ {3}}。

这有一点内存标记为只读;您也可以使用文件读写来执行此操作,但这意味着如果您写入内存,则会同时更改文件。

如果您不在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

我会检查系统上可用的内存或程序正在使用的内存。也许这会严重泄漏记忆?