realloc而不释放旧内存

realloc without freeing old memory

本文关键字:内存 释放 realloc      更新时间:2023-10-16

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

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

例如

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

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

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

例如,这是来自ucbc的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行,它在那里免费。

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

此外,这是针对ucbc的。如果您已经在使用不同的libc,那么您应该将新的tryrealloc()函数建立在该libc的realloc()函数的基础上。

编辑:如果使用这种方法,您必须小心。您的解决方案将基于内存管理器的内部,因此不同的libc实现之间以及同一libc的不同版本之间的情况可能会有所不同。因此,在做这件事的时候要注意并发出警告。

这个问题没有可移植的解决方案,不可移植的方案也不是没有风险的。

使用GNUmalloc的不可移植解决方案是使用malloc_usable_size来了解内存区域的实际大小。然而,即使内存区域足够大,我也不确定realloc是否不能保证使用它。IIRC,过去有一个选项导致realloc总是分配新内存,但我再也找不到了;不过,我看起来并不是很努力。

我不认为有一个可移植的realloc类型函数可以做到这一点。

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

一旦你超过了原来的区块,你就必须分配一个新的区块来代替它。这就是你的"失败"场景。

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

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);

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

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

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

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