为什么不释放记忆不好的做法?

dfg*_*dfg 2 c memory

int a = 0; 
int *b = malloc (sizeof(int));
b = malloc (sizeof(int));
Run Code Online (Sandbox Code Playgroud)

上面的代码很糟糕,因为它在堆上分配内存然后不释放它,这意味着您将无法访问它.但是你也创建了'a'并且从未使用它,所以你也在堆栈上分配了内存,在范围结束之前不会释放内存.

那么为什么不在堆上释放内存,但是没有释放堆栈上的内存(直到作用域结束)是不好的做法?

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

zou*_*oul 8

当范围结束时,堆栈内存将自动释放.除非您明确释放,否则堆上分配的内存将保持占用状态.举个例子:

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

for (int i=0; i<1000; i++) {
    foo();
}
Run Code Online (Sandbox Code Playgroud)

运行此代码会将可用内存减少1000*1000字节b,而所需的内存a将始终在您从foo调用返回时自动释放.

  • 内存泄漏是不可接受的......如果你的程序不再需要已分配的内存,则必须将其释放. (4认同)

Eli*_*gem 5

简单:因为你会泄漏内存.内存泄漏很糟糕.泄漏:糟糕,自由:好.
在调用malloc或者calloc实际上任何*alloc函数时,你声称有一块内存(其大小由传递给分配函数的参数定义).

与堆栈变量不同,堆栈变量驻留在内存的一部分中,程序具有一定程度的自由统治,相同的规则不适用于堆内存.你可能需要分配堆内存有多种原因:堆栈不够大,你需要一个指针数组,但无法知道这个数组在编译时需要多大,你需要共享一些内存(线程恶梦),一个需要在程序中的各个位置(函数)设置成员的结构...

其中一些原因,就其性质而言,暗示只要指向该内存的指针超出范围,就无法释放内存.另一个指针可能仍然在另一个范围内,指向同一块内存.
但是,正如其中一条评论中所提到的,这有一点点缺点:堆内存不仅需要对程序员部分有更多的认识,而且它也比在堆栈上工作更昂贵,更慢.
所以一些经验法则是:

  • 你声称了记忆,所以你要照顾它......当你完成游戏时,你确保它已被释放.
  • 没有正当理由不要使用堆内存.例如,避免堆栈溢出是一个正当理由.

无论如何,一些例子:
堆栈溢出:

#include <stdio.h>
int main()
{
    int foo[2000000000];//stack overflow, array is too large!
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

所以,这里我们耗尽了堆栈,我们需要在堆上分配内存:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int *foo= malloc(2000000000*sizeof(int));//heap is bigger
    if (foo == NULL)
    {
        fprintf(stderr, "But not big enough\n");
    }
    free(foo);//free claimed memory
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

或者,一个数组的示例,其长度取决于用户输入:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int *arr = NULL;//null pointer
    int arrLen;
    scanf("%d", &arrLen);
    arr = malloc(arrLen * sizeof(int));
    if (arr == NULL)
    {
        fprintf(stderr, "Not enough heap-mem for %d ints\n", arrLen);
        exit ( EXIT_FAILURE);
    }
    //do stuff
    free(arr);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

所以这样的例子不胜枚举......哪里还有一种情况malloc或者calloc是有用的:字符串数组,所有可能大小不等.相比:

char str_array[20][100];
Run Code Online (Sandbox Code Playgroud)

在这种情况下,str_array是一个包含20个char数组(或字符串)的数组,每个数组长100个字符.但是如果100个字符是你需要的最大值,平均而言,你只会使用25个字符或更少?
你是用C语言写的,因为它很快,你的程序不会使用比实际需要更多的资源?那不是你真正想做的事情.更有可能的是,你想:

char *str_array[20];
for (int i=0;i<20;++i) str_array[i] = malloc((someInt+i)*sizeof(int));
Run Code Online (Sandbox Code Playgroud)

现在,每个元素都str_array具有我需要分配的内存量.那更干净.但是,在这种情况下,呼叫free(str_array)不会削减它.另一个经验法则是:每个alloc调用都必须有一个free匹配它的调用,所以解除分配这个内存如下所示:

for (i=0;i<20;++i) free(str_array[i]);
Run Code Online (Sandbox Code Playgroud)

注意:
动态分配的内存不是内存泄漏的唯一原因.必须要说的是.如果您读取文件,使用打开文件指针fopen,但未能关闭该文件(fclose)也会导致泄漏:

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;
}
Run Code Online (Sandbox Code Playgroud)

编译和运行会很好,但它会包含一个泄漏,只需添加一行就可以轻松插入(并且应该插入):

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;
}
Run Code Online (Sandbox Code Playgroud)

作为一个助手:如果范围很长,你可能会试图将太多的东西塞进一个功能中.即便如此,如果你不是:你可以在任何时候释放声称的内存,它不必是当前范围的结束:

_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;
}
Run Code Online (Sandbox Code Playgroud)