【问题标题】:Does c keep track of allocated heap memory?c 是否跟踪分配的堆内存?
【发布时间】:2020-10-29 13:18:46
【问题描述】:

我知道人们一直告诉我要阅读文档,但我还没有掌握窍门。我不知道要在文档中查找什么。如果您有关于如何习惯阅读文档的提示,请给我您的提示作为奖励,但现在这是我的问题。在一个简单的程序中说,如果我们 allocate 一些内存块,我可以在完成后 free 它,对吗?这是一个这样的程序,它什么都不做,只是堆中的allocatesdeallocates 内存。

#include <stdio.h>
#include <stdlib.h>


int main(void)
{
char *s = malloc(10);
free(s);
return (0);
}

编译后,如果我们运行valgrind,我们可以看到所有东西都被释放了。现在,这里只是对之前的程序进行了一点改动。

#include <stdio.h>
#include <stdlib.h>


int main(void)
{
char *s = malloc(10);
s++;
free(s);
return (0);
}

在这里,在我释放它之前,我将地址加一,然后一切都崩溃了。 Free 现在似乎没有分配这块内存(即使它是已分配内存的子集)。如果您想查看它,这是我的错误消息。

*** Error in `./a.out': free(): invalid pointer: 0x0000000001e00011 ***
Aborted (core dumped). 

所以这让我开始思考。

  1. c 是否跟踪在堆上分配的内存
  2. 如果不是,它怎么知道什么可以释放,什么不可以?
  3. 如果它有这样的知识,为什么c在退出之前不自动deallocate这样的记忆。为什么内存泄漏?

【问题讨论】:

  • 标题中问题的答案是否定的
  • 您只能释放从malloc 等返回的内存。用其他任何东西调用 free 是未定义的行为。
  • 您的底线问题的答案是:1. 没有。 2. 没有。这是程序员的责任。 3.“它”没有“这样的知识”。虽然可以实现一个内存管理的基础设施(语言、VM 等)来防止内存泄漏,但这并不是 C 语言标准所指定的。有一些基于 C++之上构建的设计模式可以处理这些问题。您也可以在 C 中实现这些设计模式,尽管这不是在公园里散步。还有像 Java 这样的高级语言,它们使用垃圾收集来处理所有这些。
  • 这与 C 无关。这通常是操作系统的责任。如果您想知道它是如何在幕后实现的,那么AFAIK,在大多数情况下,当您在堆上分配一块内存时,操作系统实际上会在该块的开头分配几个字节,它存储长度该块和指向长度块的指针。所以本质上,堆或多或少是作为一个链表来管理的。当您通过地址(指针)删除块时,操作系统会从该地址之前的几个字节中获取元数据。
  • 我不理解反对票(以及缺乏更多赞成票):这个问题提出的很好,并显示了研究。 +1

标签: c malloc free


【解决方案1】:

free 的 C 标准描述如下:

  1. free 函数使ptr 指向的空间被释放,也就是说,可用于进一步分配。 If ptr 是一个空指针,没有动作发生。 否则,如果参数与内存管理函数先前返回的指针不匹配,或者如果空间已通过调用 free 或 realloc 释放,行为未定义。强>

由于您更改了指针,它与内存管理函数(即m/re/calloc)返回的指针不匹配,行为是未定义,任何事情都可能发生。包括运行时库,注意到您已尝试释放无效指针,但运行时也不需要这样做。


至于

  1. C 是否跟踪在堆上分配的内存

可能……但不一定必须……

  1. 如果不是,它怎么知道什么可以释放,什么不可以?

好吧,如果它确实释放了指针指向的内存,那么它显然需要对分配的大小进行某种簿记......但它不需要能够确定是否有任何指针仍然指向那个内存区域。

  1. 如果它有这样的知识,为什么 c 在退出之前不自动释放这些内存。为什么内存泄漏?

通常在操作系统退出进程后释放内存。那不是问题。真正的问题是程序仍在运行时发生的泄漏。

【讨论】:

    【解决方案2】:

    我的知识有限。但我想我可以解决你的一些问题

    1. c 是否跟踪在堆上分配的内存

    C 不跟踪任何内容。但是,操作系统会跟踪并知道哪些内存区域已使用,哪些未使用。

    1. 如果不是,它怎么知道什么可以释放,什么不可以?

    how-does-free-know-how-much-to-free
    简单地说。当调用malloc 时,你给它一个大小。 malloc 在它返回的指针前面使用 额外的 8 个字节 来“记住”这个大小信息。当你free 说指针时,free 将知道地址并读取指针前的 8 个字节以获取大小信息,然后愉快地将内存释放给操作系统。

    1. 如果它有这样的知识,为什么 c 在退出之前不自动释放这些内存。为什么内存泄漏?

    操作系统知道这些信息。因此,当 C 程序退出时,操作系统将负责并释放您没有明确释放的内存。

    *** Error in ./a.out': free(): 无效指针: 0x0000000001e00011 *** 中止(核心转储)。`

    至于这个。我给 glibc free 函数的 sn-p
    glibc malloc 将以对齐模式分配内存区域,例如 32 字节对齐。因此,当您执行 s++ 时,它不再是 32 字节对齐的。
    现在你可能会想如果我做s += 32; 并在s 之前设置一个假装的尺寸信息会怎样。我试过这个。可悲的是,我不能天真地欺骗 glibc 的 free 函数。它有其他信息可以防止这种情况发生。我现在停下来挖掘......

    【讨论】:

    • 您可能想明确指出,malloc 使用额外的 8 个字节作为标头这一事实取决于实现。另外,如果您可以添加指向屏幕截图源代码的链接,并复制粘贴代码而不是屏幕截图,那就太好了(我会帮助您:the code is here。至于为什么您不能欺骗@ 987654336@:malloc 有数据结构来跟踪空闲内存,知道何时调用sbrk 等,因此不容易被欺骗。
    • @Dada 你给我建议很有帮助。非常感谢。
    猜你喜欢
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 2012-06-10
    • 2019-05-03
    • 2022-09-27
    相关资源
    最近更新 更多