【问题标题】:What happens to a malloc'ed block if you don't use it?如果不使用 malloc 的块会怎样?
【发布时间】:2009-04-10 20:58:45
【问题描述】:

考虑以下 C 代码:

int main(){  
    int* c;  
    c = (int*)malloc(sizeof(int));  
    c = 0xdeadbeef;  
    free(c);  
    return 0;  
}

这将出现段错误,因为您正在尝试释放 c,这不是以前 malloc'ed 的东西。我的问题是我刚刚分配的块会发生什么?显然 c 不再指向它,所以它不能被使用,但它仍然被认为是“空闲”列表的一部分,还是这是一个显式的内存泄漏?

【问题讨论】:

    标签: c memory-leaks free malloc


    【解决方案1】:

    这是一个泄漏。当您的程序终止时,它会被操作系统回收。

    【讨论】:

    • 传统的Unix垃圾回收方案:运行程序,终止时回收内存。不适用于 IDE 和浏览器以及其他可能运行很长时间的程序。
    【解决方案2】:

    内存仍在分配,导致内存泄漏。你想要其他方式吗?机器/编译器确实没有办法知道您分配的内存应该被回收。如果这不是正确的行为,您的代码将按概率运行:您永远无法真正信任该代码。

    您总是可以在将来某个时间重新指向该内存块,因此自动释放它会将地毯从您的脚下拉出来。

    【讨论】:

    • 嗯,对于 C 以外的其他语言,有一些叫做垃圾收集器的东西可以为你做这件事。
    【解决方案3】:

    假设您将c = 7; 更改为*c = 7;,该代码不会出现段错误

    【讨论】:

    • free(c) 可能会出现段错误,因为 free() 将取消引用垃圾指针。
    • Majd,您在技术上是正确的(最好的正确),但是将指针更改为极其无效的地址并尝试取消引用它是他的全部观点。
    • 如果你将 c = 7 更改为 *c = 7,那就不行了。这有点离题,但他是对的
    【解决方案4】:

    在 malloc() 之后,c 是一个保存内存地址的变量。在这种情况下,c 具有您分配的第一个字节的内存地址的值。

    当您说c = 7 时,您是在说“c 现在指向内存地址'7'”。因为,在这种情况下,内存地址“7”没有分配给你的进程,你不能 free() 它。从理论上讲,内存地址“7”(或 0xa73c930bf,或您设置的任何内容)确实可能已分配给您的进程,在这种情况下 free() 会成功。

    但是,在更改 c 的值后,内存仍然被分配。您的进程仍然拥有内存及其数据 - 您刚刚丢失了指针。你不知道那段记忆从哪里开始。

    这是一个好的情况。在 C 中,您可能有不同的变量指向该内存地址。您甚至可能有一个“int”,而不是一个“int*”来存储该内存地址。 C 不会尝试跟踪您是否存储了那个特定的内存地址——这实际上只是一个数字。这样做将是一项不可能完成的任务,因为任何尝试跟踪都需要失去 C 指针提供的一些灵活性。

    所以回答您的问题:由于您无法跟踪 c 的值,因此该程序存在内存泄漏。我的意思是,您的程序可能无法使用您的内存,因此浪费了资源。

    但是,当程序退出时,分配给您的进程的所有内存都将被释放并可供其他程序使用。

    【讨论】:

    • 可以将地址存储在 int 中,但这是个坏主意。不能保证 int 和 int* 具有相同的大小和相同的表示。
    • 请记住,您可以尝试 free() 它,并且实现实际上可能会执行 free() 代码,从而更改内存。这几乎总是一件坏事,因为它在一些可能对程序的其余部分很重要的内存块上做了一些没有很好定义的事情。
    • 如果你想在整数类型变量中存储一个指针,intptr_t 就是你想要使用的。 intptr_t 足够大,可以存储任何类型的指针。
    【解决方案5】:

    请不要喷我,但我不清楚你的问题是什么意思。很明显,你正在做的事情与语言打算让你做的事情直接冲突。这相当于说“如果我用灭火器液填充汽车的油箱会发生什么,只是因为灭火器的喷嘴恰好适合油箱孔”。
    我不是想成为一个混蛋,我只是不清楚为什么这个特殊问题?我可以想出无穷无尽的问题,这些问题利用了指针的力量,想知道有多少种方法会错误地使用它们,从而导致应用程序失败。 如果您能找到正确的方法,您是否正在尝试完成您的代码*会做的事情?或者您想知道是否有某种内部机制可以跟踪您的指针并在您不小心丢失该内存时帮助您回收该内存? (如果是这样,上面已经回答了这个问题)。

    【讨论】:

      【解决方案6】:

      好吧,imo,此时出现的段错误不是因为您尝试释放以前未分配的内存,而是因为您尝试引用操作系统未授予您权限的内存地址而发生段错误给你(这是分段错误的定义)。

      一些实验,比如你会在 valgrind 中运行你的示例代码,你会得到这个作为输出:

      ==6945== 无效的 free() / delete / delete[] ==6945== 在 0x402265C: 空闲 (vg_replace_malloc.c:323) ==6945== by 0x80483D5: main (bla.c:6) ==6945== 地址 0x7 没有被堆栈、malloc 或(最近)释放 ==6945== ==6945== 错误摘要:来自 1 个上下文的 1 个错误(抑制:来自 1 个的 11 个) ==6945== malloc/free:退出时使用:1 个块中的 4 个字节。 ==6945== malloc/free:1 个分配,1 个释放,4 个字节分配。

      所以这是一个内存泄漏'pur sang'。现在假设您将更改代码,以便您尝试释放的指针“靠近”您分配的指针(因此操作系统仍然知道您可以访问它,操作系统不会授予字节边界上的内存访问权限)。假设我们这样修改代码:

      int main(){  
          int* c;  
          c = (int*)malloc(sizeof(int));  
          c++;
          free(c);  
          return 0;  
      }
      

      运行此应用程序时,您将不再收到分段错误(由内核发出),而是来自 glibc(malloc() 和 free() 的所有者)的警告

      edb@Flying-Spaghetti-Monster:/tmp$ ./a.out *** 检测到 glibc *** ./a.out: free(): 无效指针:0x0804a00c *** ...接着是一个痕迹

      所以你试图释放一些内核知道它属于你的内存,但 glibc 不记得把它交给你了。如果您在 valgrind 中运行它(通过替换 libc 中的 free()、malloc()、realloc()、... 函数并自行执行记帐),您将得到以下输出:

      ==6955== 无效的 free() / delete / delete[] ==6955== 在 0x402265C: 空闲 (vg_replace_malloc.c:323) ==6955== by 0x80483D2: main (bla.c:5) ==6955== 地址 0x418a02c 在大小为 4 的块分配后为 0 字节 ==6955== 在 0x4022AB8: malloc (vg_replace_malloc.c:207) ==6955== by 0x80483C0: main (bla.c:3) ==6955== ==6955== 错误摘要:来自 1 个上下文的 1 个错误(抑制:来自 1 个的 11 个) ==6955== malloc/free:退出时使用:1 个块中的 4 个字节。 ==6955== malloc/free:1 个分配,1 个释放,4 个字节分配。

      【讨论】:

        【解决方案7】:

        请注意,malloc() 返回的值不需要强制转换,因为转换 void* -> int* 是自动的。

        你也可以这样重写调用:

        c = malloc(sizeof *c);
        

        所以现在如果你改变c的类型,你根本不需要重写分配。

        [编辑]

        检查分配是否成功也是一个好主意(即c != NULL)。

        【讨论】:

        • 虽然在第 4 行中,需要强制转换为 (int*),否则会收到警告。
        • 对于 C,我建议将 (int *) 或其他任何东西从 malloc() 中删除。这不是必需的,它掩盖了没有#included 的可能错误。
        猜你喜欢
        • 2021-05-10
        • 2010-11-18
        • 2016-08-03
        • 2012-03-20
        • 1970-01-01
        • 1970-01-01
        • 2021-06-06
        • 2012-10-08
        • 2012-02-09
        相关资源
        最近更新 更多