【问题标题】:realloc without freeing old memory在不释放旧内存的情况下重新分配
【发布时间】:2012-12-05 21:03:40
【问题描述】:

我想使用 realloc 来增加内存大小,同时保持指针不变(因为调用者使用它)。 realloc 并不总是这样做;有时它会返回一个不同的指针并释放旧指针。我想“尝试”重新分配内存,如果不可能,请使用原始指针回退到不同的方法 - 但 realloc 已经破坏了它!

如果不可能的话,有没有办法在不破坏(如 realloc 一样)旧指针的情况下增加 malloc 的内存?

例如

void *pold;
void *pnew = realloc(pold, newsize);
if (pnew != pold)
{
     free(pnew);
     DoDifferently(pold); // but pold is freed already
}

附:我不关心可移植性(仅限 Linux,因此是标签)。

【问题讨论】:

  • 简短回答:否(好吧,无论如何都不是可移植代码 - 您可能能够深入研究标准库并调用一些未记录的内部函数来使用一个标准库的一个特定版本) .
  • 我认为这是重复的。类似(但不是欺骗)问题:stackoverflow.com/questions/6696006/…
  • @Joe:是的,他的观点是尝试重新分配到位,如果这不可能,那就失败吧。
  • @Joe 他想要一个具有这种原型的函数: bool tryrealloc(char * basePtr, size_t newSize);如果内存可以扩展,则该函数返回 True,如果该函数不能但不破坏原始内存的内容(不做任何事情),则返回 False
  • 要在扩展区域时保持指针完全相同,需要在对象“之后”有足够的可用空间。运行时系统无法收集其他对象并移动它们以腾出空间,因为这会改变程序背后的它们地址。

标签: c++ c linux gcc realloc


【解决方案1】:

我认为没有可移植的realloc-type 函数可以做到这一点。

一个相对简单的可移植解决方案是预先分配比您最初需要的更大的内存块。这将允许在不更改指针的情况下进行一些增长(实际上,您将在原地进行自己的操作realloc)。

一旦超出原始块,您就必须分配一个新块来代替它。这是你的“失败”场景。

【讨论】:

    【解决方案2】:

    为什么不只是malloc 您可能需要的最大数量?内存通常只会在您使用后才实际分配。要进行微调,您可以使用mmap 分配内存区域。

    【讨论】:

      【解决方案3】:

      据我所知,这样的事情是不可能的(使用标准库实现可移植性)。但是,有一些简单的解决方法。由于您的调用者使用该指针,因此您必须为他们修复它。一种解决方案是:

      void *do_something(void *your_pointer)
      {
          void *new_pointer;
          new_pointer = realloc(your_pointer, ...);
          /* more logic */
          return new_pointer;
      }
      

      并告诉他们像这样使用do_something

      new_pointer = do_something(my_pointer);
      if (new_pointer) /* if returning NULL is at all possible */
          my_pointer = new_pointer;
      

      或者,您可以自己处理:

      int do_something(void **pointer_to_your_pointer)
      {
          void *new_pointer;
          new_pointer = realloc(*pointer_to_your_pointer, ...);
          /* more logic */
          *pointer_to_your_pointer = new_pointer;
          return error_code;
      }
      

      并告诉他们像这样使用它:

      do_something(&my_pointer);
      

      【讨论】:

      • 不,API 是固定的,我必须保持指针不变。
      【解决方案4】:

      这个问题没有便携的解决方案,非便携的解决方案也不是没有风险。

      适用于 GNU malloc 的非便携式解决方案是使用 malloc_usable_size 找出内存区域的实际大小。但是,即使内存区域足够大,我也不确定realloc 是否不能保证使用它。 IIRC,曾经有一个选项导致realloc 总是分配新内存,但我再也找不到了;不过,我看起来并不难。

      【讨论】:

        【解决方案5】:

        您应该查看您正在使用的 libc 中的 realloc() 的源代码。从那里,应该很容易看到当它可以增加大小时所遵循的路径,以及将返回新指针的其他情况。然后,用它来编写你自己的 tryrealloc() 函数。

        例如,这是来自 uclibc 的 realloc() 源代码:http://cristi.indefero.net/p/uClibc-cristi/source/tree/nptl/libc/stdlib/malloc/realloc.c

        24  void *
        25  realloc (void *mem, size_t new_size)
        26  {
        ...
        57    if (new_size > size)
        58    /* Grow the block.  */
        59    {
        60        size_t extra = new_size - size;
        61  
        62        __heap_lock (&__malloc_heap_lock);
        63        extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra);
        64        __heap_unlock (&__malloc_heap_lock);
        65  
        66        if (extra)
        67          /* Record the changed size.  */
        68          MALLOC_SET_SIZE (base_mem, size + extra);
        69        else
        70          /* Our attempts to extend MEM in place failed, just
        71             allocate-and-copy.  */
        72        {
        73          void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE);
        74          if (new_mem)
        75            {
        76              memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE);
        77              free (mem);
        78            }
        79          mem = new_mem;
        80        }
        81      }
        ...
        

        为了清楚起见,我删除了一些部分。但是您可以在第 66 行看到,它检查是否可以简单地增加当前指针的内存。这是您要保留的部分。从第 69 行开始的else 案例用于处理将释放旧内存并返回新指针的情况。这是您想要踢出并以不同方式处理的部分。从你所说的来看,我猜你只想删除第 77 行,它在那里免费。

        如果您这样做,请记住您必须手动释放旧指针或新指针,因为现在两者都有效(并且您不希望内存泄漏)。

        另外,这是针对 uclibc 的。如果您已经在使用不同的 libc,则应将新的 tryrealloc() 函数基于该 libc 的 realloc() 函数。

        编辑:如果你使用这种方法,你必须小心。您的解决方案将基于内存管理器的内部结构,因此在各种 libc 实现之间以及同一 libc 的不同版本之间,情况可能会发生变化和不同。因此,请牢记适当的注意和警告。

        【讨论】:

        • 所以你建议他使用__heap_alloc_at(如果有的话)?使用内部函数并不是一个好主意,因为它们不仅会在库之间发生变化,而且还会在同一库的不同版本之间发生变化。它今天可以工作,但很可能明天不行。
        • @Shahbaz 不,我建议他查看他正在使用的 libc 版本,并根据该 libc 的 realloc() 编写自己的 tryrealloc() 函数。但这是事实,同一库的不同版本可能会发生变化,因此我也会对此添加警告。
        【解决方案6】:

        程序员手中没有reallocate 相同的指向memory region.. 您可以使用realloc() 增加size.. 使用@ 后您可能会或可能不会得到相同的memory location 987654326@..很可能你不会..如果内存位置发生变化,可能没有任何问题..

        【讨论】:

          【解决方案7】:

          替代的内存管理库jemalloc 提供了这样的功能。使用xallocx() 可以这样做:

          size_t realsize = xallocx(pold, newsize, 0, 0);
          if (realsize < newsize)
          {
               DoDifferently(pold);
          }
          

          【讨论】:

            猜你喜欢
            • 2014-08-16
            • 1970-01-01
            • 2014-04-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-29
            • 2012-04-10
            • 2014-03-15
            相关资源
            最近更新 更多