C - 大输入时的内存泄漏

C - memory leak in case of big input

对于作业,我必须订购一份学生名单。每个人都由一个数字(大小为 15 的字符串)、他父亲的姓氏(字符串 20)、他母亲的姓氏(字符串 20)和他的名字(字符串 20)表示。

我做了一个程序,它从一个文件构建学生列表并对其进行排序(我使用合并排序来这样做)。

当我 运行 小部分学生(<10 000)的程序一切正常(根据 valgrind 没有内存泄漏或任何东西)。

但是,当我尝试在更大的(超过 100 000)上使用它时,我得到了分段错误 11。我调查了 Valgrind,它说错误来自 strcy 或 strcasecmp 函数,并且渲染:

==2433== Invalid write of size 8
==2433==    at 0x4019BD: merge (sort.c:59)
==2433==    by 0x40173B: sortBeginEnd (sort.c:38)
==2433==    by 0x4014B0: sortWithoutInterval (sort.c:9)
==2433==    by 0x401EE0: firstSort (sort.c:166)
==2433==    by 0x4009EB: main (main.c:44)
==2433==  Address 0xffe79ac88 is on thread 1's stack
==2433== 
==2433== 
==2433== Process terminating with default action of signal 11 (SIGSEGV)
==2433==  Access not within mapped region at address 0xFFE79AC88
==2433==    at 0x4019BD: merge (sort.c:59)
==2433==  If you believe this happened as a result of a stack
==2433==  overflow in your program's main thread (unlikely but
==2433==  possible), you can try to increase the size of the
==2433==  main thread stack using the --main-stacksize= flag.
==2433==  The main thread stack size used in this run was 8388608.
==2433== 
==2433== Process terminating with default action of signal 11 (SIGSEGV)
==2433==  Access not within mapped region at address 0xFFE79AC81
==2433==    at 0x4A256B0: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so)
==2433==  If you believe this happened as a result of a stack
==2433==  overflow in your program's main thread (unlikely but
==2433==  possible), you can try to increase the size of the
==2433==  main thread stack using the --main-stacksize= flag.
==2433==  The main thread stack size used in this run was 8388608.
==2433== 
==2433== HEAP SUMMARY:
==2433==     in use at exit: 12,800,101 bytes in 500,007 blocks
==2433==   total heap usage: 500,008 allocs, 1 frees, 12,800,669 bytes allocated
==2433== 
==2433== LEAK SUMMARY:
==2433==    definitely lost: 0 bytes in 0 blocks
==2433==    indirectly lost: 0 bytes in 0 blocks
==2433==      possibly lost: 0 bytes in 0 blocks
==2433==    still reachable: 12,800,101 bytes in 500,007 blocks
==2433==         suppressed: 0 bytes in 0 blocks
==2433== Rerun with --leak-check=full to see details of leaked memory
==2433== 
==2433== For counts of detected and suppressed errors, rerun with: -v
==2433== ERROR SUMMARY: 7452721 errors from 31 contexts (suppressed: 0 from 0)

错误可能是我使用了太多内存(每个学生代表 79 个字符 = 316 字节,我有 100 000 个字符,所以如果我是对的,它是 31 600 000 字节)?

PS : 我对栈和堆的概念不是很熟悉

编辑:

"Everything is fine" valgrind 报告:

==2454== 
==2454== HEAP SUMMARY:
==2454==     in use at exit: 0 bytes in 0 blocks
==2454==   total heap usage: 50,008 allocs, 50,008 frees, 1,280,669 bytes allocated
==2454== 
==2454== All heap blocks were freed -- no leaks are possible
==2454== 
==2454== For counts of detected and suppressed errors, rerun with: -v
==2454== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

编辑2:

代码可用here如果你想检查它。

最后编辑:

感谢@Lundin 的回答,我终于找到了解决方案。问题是我没有使用 malloc 为 mergeSort 的合并部分分配临时数组。

我会再调查一下 heap/stack 的问题,以完全理解这个问题。

堆栈是您的函数保存其 local/temporary 数据(参数和局部变量)的地方。它被组织成一堆纸,所以当你调用一个函数时,参数被放入堆栈,当函数完成时,除了结果之外的所有东西都被从堆栈中丢弃。通常堆栈的大小有限。

堆是内存,您分配的数据保存在其中 (f.e.malloc())。你可以有不同的堆(对于你的应用程序,对于每个进程和系统范围)

你甚至没有提到这是针对哪个系统的。由于 Valgrind,我假设 Linux。你没有提到你在哪里分配变量。显然不在堆上,因为 Valgrid 在那里只报告 12.8kb。

如果我没记错的话(我对 Linux 知之甚少)进程的堆栈大小大约为 8Mb。

316 *  10000 =  3.16 Mb. 
316 * 100000 = 31.60 Mb. 

合格的猜测:如果您使用 malloc 以外的任何其他方式分配变量,那么堆栈溢出就是所描述问题的根源。

只要在程序中使用大量内存,就必须在堆上动态分配它们。