realloc没有释放旧记忆

时间:2012-12-18 15:53:18

标签: c++ c linux gcc realloc

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

有没有办法尝试增加malloc的内存而不破坏(如同realloc那样)旧指针(如果不可能的话)?

E.g。

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

P.S。我不关心可移植性(仅限linux,因此标签)。

7 个答案:

答案 0 :(得分:3)

您应该从您正在使用的libc中查看realloc()的源代码。从那里开始,应该很容易看到当它可以增加大小时所遵循的路径,以及将返回新指针的else情况。然后,使用它来编写自己的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的不同版本之间也会发生变化。所以在考虑到适当的关怀和警告的情况下这样做。

答案 1 :(得分:1)

我认为没有便携式realloc类型的功能可以做到这一点。

一个相对简单的便携式解决方案是预先分配比最初需要的更大的内存块。这样就可以在不改变指针的情况下实现一些增长(实际上,你将在原地realloc做自己的事情。)

一旦超过原始区块,您将不得不分配一个新区块。这是你的失败"场景。

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

此问题没有可移植的解决方案,非便携式解决方案没有风险。

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

答案 4 :(得分:1)

备用内存管理库jemalloc提供此类功能。使用xallocx()可以这样做:

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

答案 5 :(得分:0)

为什么不只是malloc您可能需要的最高金额?通常只有在你使用它时才会实际分配内存。要进行微调,您可以使用mmap来分配内存区域。

答案 6 :(得分:0)

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