【问题标题】:Can I still call free() on a variable that had a second malloc() call on it?我仍然可以对一个有第二个 malloc() 调用的变量调用 free() 吗?
【发布时间】:2019-02-11 04:23:40
【问题描述】:

当涉及到系统如何释放内存时,我想知道 malloc() 调用是否与您分配 malloc() 的初始变量相关联。

例如,我可以执行以下操作吗:

void * ptr1 = malloc(50);
void * ptr2 = ptr1;
ptr1 = malloc(25);
free(ptr2);

我打算释放 最初分配给 ptr1 的内存,但后来被另一个指针释放了。

【问题讨论】:

  • 你必须释放你 malloc 的每个块。谁当前指向该块并不重要。你已经成功地释放了这里的 50 字节块,但是你的 25 字节块是悬空的。
  • @LeeDanielCrocker:必须吗?
  • 好吧,在出口处留下可到达的街区不是问题,但这是马虎的证据。
  • 误会:你free不是一个变量,你freemalloc之前获得的某个内存区域,它是一个指针值 (可以保存在 C 源代码的 几个 变量中,也可以不保存)
  • @LeeDanielCrocker:一个例外是在大型应用程序中,所有所需的上下文结束都已执行并且系统性能很有价值。那么进行进程内簿记就没有意义了,当进程终止时,它只会被抹去。当然,管理这种“退出不干净”的行为本身就是一个挑战,因为你不想在仅仅清理进程中的子任务而不是最终退出时忘记分配的内存。

标签: c memory malloc


【解决方案1】:

让我们一步一步来看看(UNDEF 表示我们不知道值是什么;valid 表示指针可以安全使用):

void *ptr1, *ptr2;    /* ptr1=UNDEF (invalid), ptr2=UNDEF (invalid) */
ptr1 = malloc(50);    /* ptr1=0xAAA (valid),   ptr2=UNDEF (invalid) */
ptr2 = ptr1;          /* ptr1=0xAAA (valid),   ptr2=0xAAA (valid)   */
ptr1 = malloc(25);    /* ptr1=0xBBB (valid),   ptr2=0xAAA (valid)   */
free(ptr2);           /* ptr1=0xBBB (valid),   ptr2=UNDEF (invalid) */

free() 不知道它所传递的指针存储在哪个如果有变量中;不保证(但也不保证)以任何方式更新或与变量交互。从应用程序开发人员的角度来看,所有有效的变化是实际使用该指针是否安全,或者对在返回它的malloc() 调用期间分配的内存块的任何其他引用是否安全。

正如@M.Min comments 所提到的,C 语言规范明确指出指向已释放对象的指针的值是未定义的,并且允许编译器以任何方式对其进行修改;更多讨论请参见Why does MISRA C state that a copy of pointers can cause a memory exception?

【讨论】:

  • C11 6.2.4/2 "当指针指向(或刚刚过去)的对象达到其生命周期结束时,指针的值变得不确定。" . 7.22.3/1 表示动态分配的对象的生命周期在其被释放时结束,而 7.22.3.3 则表示free 导致对象被释放。
【解决方案2】:

简短回答:是的

更长的答案:

您不是在“对变量”调用 free,而是对存储在变量中的

为了更好地理解发生了什么,最好将内存视为一个大字节数组,并将指针可视化为该数组的数字索引。在您可能遇到的大多数架构中,这实际上是幕后发生的事情。

当你这样做时

void * ptr1 = malloc(50);

malloc 正在保留一个 50 字节的块并返回一个指向该块的指针。该指针只不过是一个数字索引,告诉我们保留块在内存中的哪个位置开始。

理论上我们可以(在某些架构上)写

int ptr1 = (int)malloc(50);

我们不这样做的原因是:

  1. sizeof(int) 可能不够大,无法容纳指针
  2. void * 告诉编译器存储在ptr1 中的数值应被视为内存地址。

如果我们继续查看您的代码:

void * ptr2 = ptr1;

这里没有什么神奇的事情发生。存储在ptr1 中的“数值”被复制到ptr2,就像ptr1ptr2 是普通的整数变量一样。

ptr1 = malloc(25);

在这里你用一个新的“数值”覆盖ptr1的内容,但是旧的值 ptr2 中仍作为副本存在。

free(ptr2);

在这里您调用free,并将值存储在ptr2 中。这是malloc(50) 返回的值。 free 不关心哪个变量持有那个值/地址。它只关心值/地址指向用malloc 保留的内存块的第一个字节。

理论上,如果您知道 malloc(50) 返回值 0xb00b1e5,您可以这样做

free((void *) 0xb00b1e5);

但是您无法安全地预测 malloc 会返回什么,所以不要那样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-18
    • 1970-01-01
    • 2021-05-12
    • 2019-01-02
    • 2022-06-14
    • 2011-05-24
    • 1970-01-01
    相关资源
    最近更新 更多