【问题标题】:What would realloc do if there is no sequential space of memory?如果没有顺序的内存空间,realloc 会做什么?
【发布时间】:2011-04-10 16:51:17
【问题描述】:

realloc用于动态重新分配内存。

假设我使用 malloc 函数分配了 7 个字节,现在我想将其扩展为 30 个字节。

如果内存中没有连续(连续单行)的 30 字节空间,后台会发生什么?

是否有任何错误或将部分分配内存?

【问题讨论】:

    标签: c dynamic-memory-allocation realloc


    【解决方案1】:

    FreeBSD 和 Mac OS X 具有 reallocf() 函数,当请求的内存无法分配时,该函数将释放传递的指针(参见 man realloc)。

    【讨论】:

    • 如果你真的想要这种行为,那么编写自己的函数来这样做会更有意义,而不是使用它。但我无法想象它非常有用 - 它会丢弃可能有价值的数据。
    【解决方案2】:

    realloc 在幕后的工作大致是这样的:

    • 如果当前块后面有足够的可用空间来满足请求,则扩展当前块并返回指向块开头的指针。
    • 否则,如果其他地方有足够大的空闲块,则分配该块,从旧块复制数据,释放旧块并返回指向新块开头的指针
    • 否则返回NULL 报告失败。

    因此,您可以通过测试NULL 来测试失败,但请注意不要过早覆盖旧指针:

    int* p = malloc(x);
    /* ... */
    p = realloc(p, y); /* WRONG: Old pointer lost if realloc fails: memory leak! */
    /* Correct way: */
    {
      int* temp = realloc(p, y);
      if (NULL == temp)
      {
        /* Handle error; p is still valid */
      }
      else
      {
        /* p now possibly points to deallocated memory. Overwrite it with the pointer
           to the new block, to start using that */
        p = temp;
      }
    }
    

    【讨论】:

    • realloc 适用于所有实现吗?
    • @CoolGuy:某些实现可能无法(能够)执行扩展当前块的第一步,但除此之外,这是所有实现realloc 的可观察行为。
    【解决方案3】:

    一般来说,这取决于实现。在 x86(-64) Linux 上,我相信标准的 doug lea malloc 算法将始终分配至少一个标准的 x86 页面(4096 字节),因此对于您上面描述的场景,它只会重置边界以容纳额外的字节。比如说,将 7 字节的缓冲区重新分配给 PAGE_SIZE+1,我相信它会尝试分配下一个可用的连续页面。

    如果您在 Linux 上开发,请阅读以下内容:

    默认情况下,Linux 遵循乐观的内存分配策略。这意味着当 malloc() 返回非 NULL 时,不能保证内存确实可用。这是一个真的 坏虫子。如果发现系统内存不足,一个或多个进程将被臭名昭著的 OOM 杀手杀死。万一 Linux 在可能的情况下使用 突然丢失一些随机选择的进程不太可取,而且内核版本足够新,可以使用以下命令关闭这种过度使用行为:

    # echo 2 > /proc/sys/vm/overcommit_memory
    

    另请参阅内核文档目录、文件 vm/overcommit-accounting 和 sysctl/vm.txt。

    【讨论】:

      【解决方案4】:

      来自man page

      realloc() 返回一个指向 新分配的内存,即 适合任何类型的对齐 变量并且可能不同于 ptr,如果请求失败,则为 NULL。

      也就是说,要检测失败,只需检查结果是否为NULL。

      编辑:如评论中所述,如果调用失败,则不会释放原始内存。

      【讨论】:

      • 值得从手册页中注意:如果 realloc() 失败,则原始块保持不变;它没有被释放或移动。
      【解决方案5】:

      realloc 只有在它可以返回一个连续的(用你的话来说是“顺序的”)内存块时才会成功。如果不存在这样的块,它将返回NULL

      【讨论】:

      • @Mark - 原始内存保持不变。这种情况下的一个常见错误是 'x=realloc(x)' - 您必须执行 'newX=realloc(x)' 以避免在错误时泄漏原始 x。
      • @Steve Townsend - 只有在仪式失败的情况下?成功后,它会释放原始指针。这个页面上的马克是谁? O_o
      • 我猜有一个错误。第一条评论来自用户 sharptooth,现在它已更改,尽管两者都是针对 Mark 的。那是一个错误吗? :-P
      • @Praveen - 我的评论是针对一个现已删除的早期评论。是的,我展示的用法仍然是一个错误。成功后,它会释放原始指针(如果可以将连续的较大块锚定在那里,则将其返回给您再次使用)。
      • @Steve:如果您使用if (!x) exit(1); 关注它,这不是错误:-)
      猜你喜欢
      • 2013-12-16
      • 2020-12-23
      • 1970-01-01
      • 2016-08-23
      • 2014-07-10
      • 2011-12-06
      • 2021-02-02
      • 2011-05-10
      • 1970-01-01
      相关资源
      最近更新 更多