C 为什么释放内存不是一个坏习惯?

C 为什么释放内存不是一个坏习惯?,c,memory,C,Memory,上面的代码很糟糕,因为它在堆上分配内存,然后不释放内存,这意味着您失去了对它的访问。但是您也创建了“a”并且从未使用过它,所以您也在堆栈上分配了内存,直到作用域结束才会释放内存 那么,为什么不释放堆上的内存而不释放堆栈上的内存(直到作用域结束)是不好的做法呢 注意:我知道堆栈上的内存无法释放,我想知道为什么它不被认为是坏的。当作用域结束时,堆栈内存将自动释放。除非显式释放,否则在堆上分配的内存将保持占用状态。例如: int a = 0; int *b = malloc (sizeof(int)

上面的代码很糟糕,因为它在堆上分配内存,然后不释放内存,这意味着您失去了对它的访问。但是您也创建了“a”并且从未使用过它,所以您也在堆栈上分配了内存,直到作用域结束才会释放内存

那么,为什么不释放堆上的内存而不释放堆栈上的内存(直到作用域结束)是不好的做法呢


注意:我知道堆栈上的内存无法释放,我想知道为什么它不被认为是坏的。

当作用域结束时,堆栈内存将自动释放。除非显式释放,否则在堆上分配的内存将保持占用状态。例如:

int a = 0; 
int *b = malloc (sizeof(int));
b = malloc (sizeof(int));
void foo(void){
int a=0;
void*b=malloc(1000);
}

对于(int i=0;i我想这与作用域“结束”(在函数末尾)有关,这意味着如果您从该函数返回创建
a
并分配
b
,您将在某种意义上释放
a
占用的内存,并丢失
b
使用的其余执行内存


尝试调用该函数几次,很快就会耗尽所有内存。堆栈变量不会出现这种情况(缺陷递归除外)

当函数离开时,会自动回收局部变量的内存(通过重置帧指针).

问题是,在程序结束之前,您在堆上分配的内存永远不会被释放,除非您显式地释放它。这意味着每次分配更多堆内存时,您都会越来越多地减少可用内存,直到程序最终耗尽(理论上)


堆栈内存是不同的,因为它是按照编译器确定的可预测模式进行布局和使用的。它根据给定块的需要展开,然后在块结束时收缩。

简单:因为你会泄漏内存。内存泄漏是坏的。泄漏:坏,可用:好。
当调用
malloc
calloc
或任何*alloc函数时,您都在声明一块内存(其大小由传递给分配函数的参数定义)

与堆栈变量不同,堆栈变量驻留在程序有一定自由支配权的内存中,相同的规则不适用于堆内存。您可能需要分配堆内存,原因有很多:堆栈不够大,您需要一个指针数组,但无法知道在编译时这个数组需要有多大,您需要共享一些内存块(线程噩梦),该结构要求在程序中的不同位置(函数)设置成员

其中一些原因本质上意味着,一旦指向该内存的指针超出作用域,就无法释放该内存。另一个指针可能仍在另一个作用域中,指向同一内存块。
不过,正如其中一条评论中所提到的,这有一个小小的缺点:堆内存不仅需要程序员有更多的意识,而且比在堆栈上工作更昂贵、更慢。
因此,一些经验法则是:

  • 你已经申请了内存,所以你要保管好它…你要确保当你玩完它的时候它会被释放
  • 在没有有效原因的情况下不要使用堆内存。例如,避免堆栈溢出是一个有效的原因
反正, 一些例子:
堆栈溢出:

void foo(void) {
    int a = 0;
    void *b = malloc(1000);
}

for (int i=0; i<1000; i++) {
    foo();
}
在本例中,
str\u array
是一个由20个字符数组(或字符串)组成的数组,每个数组的长度为100个字符。但如果100个字符是您所需的最大值,并且平均仅使用25个字符或更少,该怎么办?
您使用C语言编写,因为它速度快,并且您的程序不会使用超出实际需要的资源?那么这并不是您真正想要做的。更可能的情况是,您想要:

char str_array[20][100];
注:
动态分配的内存不是mem泄漏的唯一原因。必须指出,如果您读取文件,使用
fopen
打开文件指针,但未能关闭该文件(
fclose
),也会导致泄漏:

for (i=0;i<20;++i) free(str_array[i]);
将很好地编译和运行,但它将包含一个漏洞,只需添加一行即可轻松堵塞(应该堵塞):

int main()
{//LEAK!!
    FILE *fp = fopen("some_file.txt", "w");
    if (fp == NULL) exit(EXIT_FAILURE);
    fwritef(fp, "%s\n", "I was written in a buggy program");
    return 0;
}
附带说明:如果作用域很长,很可能是您试图在单个函数中塞进太多。即使如此,如果您没有:您可以在任何时候释放声明的内存,它不必是当前作用域的结尾:

int main()
{//OK
    FILE *fp = fopen("some_file.txt", "w");
    if (fp == NULL) exit(EXIT_FAILURE);
    fwritef(fp, "%s\n", "I was written in a bug-free(?) program");
    fclose(fp);
    return 0;
}
因为在其他答案中多次提到的堆栈和堆有时会被误解,甚至在C程序员中也是如此,讨论这个话题

那么,为什么不释放堆上的内存而不释放堆栈上的内存(直到作用域结束)是不好的做法呢

堆栈上的内存(例如分配给自动变量的内存)将在退出创建它们的作用域时自动释放。
scope
是指全局文件或函数,还是指函数中的块({…})内。
但是堆上的内存,例如使用
malloc()
calloc()
,甚至
fopen()
创建的内存,分配的内存资源在使用
free()
fclose()明确释放之前不会用于任何其他用途

到<强>说明为什么在不释放内存的情况下分配内存是不好的:< /强>,考虑如果应用程序被设计为自动运行很长时间会发生什么,比如应用在PID回路中控制您的汽车上的巡航控制。并且,在该应用程序中有未释放的存储器,以及AF。在运行3个小时后,微处理器中的可用内存耗尽,导致PID突然运行。“啊!”你说,“这永远不会发生!”(不完全是sam

char *str_array[20];
for (int i=0;i<20;++i) str_array[i] = malloc((someInt+i)*sizeof(int));
for (i=0;i<20;++i) free(str_array[i]);
int main()
{//LEAK!!
    FILE *fp = fopen("some_file.txt", "w");
    if (fp == NULL) exit(EXIT_FAILURE);
    fwritef(fp, "%s\n", "I was written in a buggy program");
    return 0;
}
int main()
{//OK
    FILE *fp = fopen("some_file.txt", "w");
    if (fp == NULL) exit(EXIT_FAILURE);
    fwritef(fp, "%s\n", "I was written in a bug-free(?) program");
    fclose(fp);
    return 0;
}
_Bool some_long_f()
{
    int *foo = malloc(2000000000*sizeof(int));
    if (foo == NULL) exit(EXIT_FAILURE);
    //do stuff with foo
    free(foo);
    //do more stuff
    //and some more
    //...
    //and more
    return true;
}
#include <ansi_c.h>
char *buf=0;

int main(void)
{
    long long i;
    char text[]="a;lskdddddddd;js;'";

    buf = malloc(1000000);

    strcat(buf, "a;lskdddddddd;js;dlkag;lkjsda;gkl;sdfja;klagj;aglkjaf;d");
    i=1;    
    while(strlen(buf) < i*1000000)
    {
        strcat(buf,text); 
        if(strlen(buf) > (i*10000) -10)
        {
            i++;
            buf = realloc(buf, 10000000*i); 
        }
    }
    return 0;   
}  
while ( some_condition() )
{
  int x;
  char *foo = malloc( sizeof *foo * N );

  // do something interesting with x and foo
}