我刚刚读完K& R,这就是我所知道的所有C语言。我的所有编译都是使用MinGW从Windows命令行完成的,我不了解高级调试方法(因此我的第二个程序中的“ghetto debug”注释)。
我正在尝试制作一些小型测试程序,以帮助我更好地理解内存分配的工作原理。这些前几个程序不使用malloc或free,我只是想看看如何为函数本地的标准数组分配和解除分配内存。我的想法是,我观察我的运行进程RAM使用情况,看它是否符合我的理解。对于下面的第一个程序,它确实按预期工作。 alloc_one_meg()
函数分配并初始化250,000个4字节整数,但只要函数返回就会取消分配MB。因此,如果我连续10000次调用该函数,我永远不会看到我的RAM使用量远远高于1MB。而且,它有效。
#include <stdio.h>
#include <stdlib.h>
void alloc_one_meg() {
int megabyte[250000];
int i;
for (i=0; i<250000; i++) {
megabyte[i] = rand();
}
}
main()
{
int i;
for (i=0; i<1000000; i++) {
alloc_one_meg();
}
}
对于下面的第二个程序,我们的想法是不允许函数退出,同时运行1000个相同函数的副本,这是我用递归完成的。我的理论是,在递归完成之后,程序将消耗1GB的RAM,然后再将其全部解除分配。但是,它不会通过递归超过第二个循环(请参阅我的ghetto调试注释)。该程序崩溃了一个非信息性(对我而言)的消息(Windows弹出窗口说____。exe遇到了问题)。通常我总是可以通过我的贫民窟调试方法找到问题的根源......但它在这里不起作用。我很难过。这段代码有什么问题?谢谢!
#include <stdio.h>
#include <stdlib.h>
int j=0;
void alloc_one_meg() {
int megabyte[250000];
int i;
for (i=0; i<250000; i++) {
megabyte[i] = rand();
}
j++;
printf("Loop %d\n", j); // ghetto debug
if (j<1000) {
alloc_one_meg();
}
}
main()
{
alloc_one_meg();
}
发布了here后续问题。
答案 0 :(得分:3)
你正在遇到堆栈溢出。
本地自动存储变量(例如megabyte
)在堆栈上分配,其空间有限。 malloc在堆上分配,这允许更大的分配。
您可以在这里阅读更多内容:
http://en.wikipedia.org/wiki/Stack_overflow
(我应该注意,C语言没有指定内存的分配位置 - 堆栈和堆是实现细节)
答案 1 :(得分:2)
Windows程序中堆栈的大小通常约为1 MB,因此在第二次递归时,堆栈溢出。你不应该在堆栈上分配这么大的数组,使用malloc
和free
来分配和释放堆上的内存(对于这样的大小,你无法绕过malloc
阵列):
void alloc_one_meg() {
int *megabyte = malloc(sizeof(int) * 250000); // allocate space for 250000
// ints on the heap
int i;
for (i=0; i<250000; i++) {
megabyte[i] = rand();
}
j++;
printf("Loop %d\n", j); // ghetto debug
if (j<1000) {
alloc_one_meg();
}
free(megabyte); // DO NOT FORGET THIS
}
那就是说,你实际上可以改变程序的堆栈大小并使其更大(虽然我只是作为教育练习而不是生产代码)。对于Visual Studio,您可以use the /F compiler option,在Linux上,您可以使用setrlimit(3)
。我不知道MinGW应该使用什么。
答案 2 :(得分:1)
通过递归函数调用分配的内存是从堆栈中分配的。所有堆栈内存必须是连续的。当您的进程启动一个线程时,Windows将为该线程的堆栈保留一系列虚拟内存地址空间。要保留的内存量在EXE文件&#34; PE头中指定。&#34; PE代表&#34; Portable Executable。&#34;
使用Visual Studio附带的dumpbin
实用程序,将其自身(dumpbin.exe
)作为输入文件:
dumpbin /headers dumpbin.exe
...有一些输出,然后:
100000 size of stack reserve
2000 size of stack commit
&#34; 100000&#34;是十六进制数字,等于1,048,576,所以这代表大约1MB。
换句话说,操作系统只会为堆栈保留1MB的地址范围。当该地址范围用完时,Windows可能会或可能无法分配更多连续的内存范围来增加堆栈。结果取决于是否有更进一步的连续地址范围。由于Windows在线程开始时进行了其他分配,因此它不太可能可用。
要在Windows下分配最大数量的虚拟内存,请使用VirtualAlloc
系列函数。
答案 3 :(得分:0)
StackOverflow的。这是一个棘手的问题吗?