如何在内存失败时处理realloc?

时间:2009-12-31 18:27:23

标签: c memory realloc

问题说明了这一切,但这是一个例子:

typedef struct mutable_t{
    int count, max;
    void **data;
} mutable_t;


void pushMutable(mutable_t *m, void *object)
{
    if(m->count == m->max){
        m->max *= 2;
        m->data = realloc(m->data, m->max * sizeof(void*));
    }
    // how to handle oom??
    m->data[m->count++] = object;
}

如何处理内存耗尽而不是处理所有数据?

编辑 - 让我们假设有一些事情可以做,例如在某处释放一些记忆或者至少告诉用户“你不能那样做 - 你的记忆力不足”。理想情况下,我想留下那里分配的内容。

8 个答案:

答案 0 :(得分:22)

标准技术是引入一个新变量来保存realloc的返回值。然后,如果成功,则只覆盖输入变量:

tmp = realloc(orig, newsize);
if (tmp == NULL)
{
    // could not realloc, but orig still valid
}
else
{
    orig = tmp;
}

答案 1 :(得分:8)

realloc()失败时应采取的措施取决于您的申请。这个问题过于笼统,无法回答所有可能的案例。

其他一些说明:

永远不要:

a = realloc(a, size);

如果realloc()失败,则会丢失原始指针,而realloc()不会free()原始内存,因此会出现内存泄漏。相反,做:

tmp = realloc(a, size);
if (tmp)
    a = tmp;
else
    /* handle error */

我想做的第二点是次要的,可能不是那么重要,但无论如何要了解它是很好的:增加由f因子分配的内存是好的。我们先说malloc() n 字节。然后你需要更多的内存,所以realloc()的大小 n×f 。然后你需要更多的内存,所以你需要 n×f 2 字节。如果希望realloc()使用前两个内存块中的空格,则需要确保 n×f 2 ≤n+ n×f 。求解这个等式,得到f≤(sqrt(5)+1)/ 2 = 1.618 Golden ratio)。我大部分时间都使用1.5因子。

答案 2 :(得分:7)

这是一个热点按钮主题,因为在这个主题上基本上有两种思想流派

  1. 检测OOM,并使该函数返回错误代码。
  2. 检测OOM并尽快崩溃您的流程
  3. 我个人在营地#2。对于非常特殊类型的应用程序,OOM是致命期。确实,完美编写的代码可以处理OOM,但很少有人理解如何编写在没有内存的情况下安全的代码。实际上做的更少,因为它几乎不值得付出努力。

    我不喜欢将错误代码传递给OOM的调用函数,因为它相当于告诉调用者“我失败了,你无能为力”。相反,我更喜欢快速崩溃,因此产生的转储尽可能具有指导性。

答案 3 :(得分:3)

使用realloc时,您应该遵循的第一条规则是不将realloc的返回值分配给传递给它的同一指针。这个

m->data = realloc(m->data, m->max * sizeof(void*)); 

很糟糕。如果realloc失败,则返回空指针,但不释放旧内存。上面的代码将使m->data为空,而m->data以前指向的旧内存块很可能会成为内存泄漏(如果没有其他引用)。

realloc的返回值应首先存储在单独的指针中

void **new_data;
...
new_data = realloc(m->data, m->max * sizeof(void*)); 

然后,您可以检查成功/失败,并在成功的情况下更改m->data的值

if (new_data != NULL)
  m->data = new_data;
else
  /* whatever */;

答案 4 :(得分:2)

这完全是你的问题!以下是一些标准:

  • 你问这个记忆是有原因的。如果它不可用,你的程序工作是否注定失败还是可以继续做?如果是前者,您希望使用错误消息终止程序;否则,您可以以某种方式显示错误消息并继续。

  • 是否有可能换空间?您可以使用使用较少内存的算法回复您尝试的任何操作吗?这听起来像是很多工作,但实际上有可能在最初没有足够的内存的情况下继续执行程序。

  • 如果没有这些数据且内存不足,你的程序是否继续跛行是不是错了?如果是这样,您应该以错误消息终止。杀死你的程序比盲目地继续处理不正确的数据要好得多。

答案 5 :(得分:2)

  1. 了解应用程序框架如何处理OOM。许多人根本不会处理OOM。大多数情况下,框架在无空闲RAM条件下无法正常运行,除非它在某个地方非常明确且明确地说明了它。如果框架不能处理OOM并且是多线程的(现在很多都是如此),那么在许多情况下,OOM将成为该过程的结束。即使它不是多线程的,它仍然可能接近崩溃。退出流程还是框架确实可能是一个有争议的问题;可预测的立即退出可能比在不久的将来某个半随机点崩溃要好一些。

  2. 如果您正在使用一个单独的专用子内存池(即不是您通常的malloc)来获得一组定义明确的操作,这些操作仅限于OOM在内存中的使用(即当前操作是在OOM上为子内存池而不是整个进程或主内存池干净地回滚或中止,并且该子池也不被应用程序框架使用,或者如果你的框架和其他部分的整个应用程序旨在维持有意义的状态并在非自由RAM条件下继续运行(在内核模式和某些类型的系统编程中很少见但不是闻所未闻)您可能正确地返回错误代码而不是使进程崩溃。

  3. 理想情况下,处理过程中的大部分内存分配(或者更理想的是所有分配)应该在处理过程中尽快分配,理想情况是在正确开始之前,最小化数据完整性丢失和/或失败时所需的回滚编码量的问题。在实践中,很多时候,为了节省编程成本和项目时间,保护数据完整性应用程序依赖于数据库事务,并要求用户/支持人员检测GUI崩溃(或服务器崩溃)并在外出时重新启动应用程序发生内存错误,而不是以最佳方式编写以应对和回滚任何和所有数千个潜在的OOM情况。然后,工作重点是尝试限制应用程序暴露于超载情况,这可能包括额外的验证和数据大小限制以及同时连接和查询。

  4. 即使您检查报告的内存量是多少,通常其他代码可能会像您一样分配或释放内存,更改内存检查的基础并可能导致OOM。因此,在分配之前检查可用的可用RAM通常不是解决确保应用程序在可用RAM限制内运行并保持数据完整性足以满足用户的问题的可靠解决方案。

  5. 最好的情况是知道应用程序在所有可能的情况下需要多少内存,包括任何框架开销,并将该数字保持在应用程序可用的RAM量之内,但系统通常是如此复杂的外部依赖性决定了数据大小,因此实现这一点可能是不现实的。

  6. 酸性测试当然是通过高正常运行时间和不经常的数据损坏,丢失或崩溃来充分满足用户。在某些情况下,具有监视进程的应用程序在崩溃时重新启动它是有用的。

    关于realloc:

    检查realloc的返回值 - 将其放在临时变量中。如果请求的新大小为> 0,则只关注它是否为NULL。在其他情况下,将其放在非临时变量中:

    例如

        void* temp = realloc(m->data, m->max * sizeof(void*));
        if (m->max!=0&&temp==NULL) { /* crash or return error */ }
        m->data =(void**)temp;
    

    修改

    在(1)中将“大多数情况”改为“很多情况”。

    我认识到,如果无法分配内存,你会假设“可以做某事”。但内存管理是一个非常全面的考虑因素(!)。

答案 6 :(得分:1)

还有另一个可以来自realloc的微妙错误。来自返回的NULL指针的内存泄漏是众所周知的(但很难偶然发现)。 我在程序中偶然发生了一次来自realloc调用的崩溃。我有一个动态结构,通过类似这个的realloc自动调整其大小:

m->data = realloc(m->data, m->max * sizeof(void*)); 

我犯的错误是没有检查m-> max == 0,这释放了内存区域。并且使用我的m->数据指针制作了一个陈旧的数据。

我知道这有点偏离主题,但这是我对realloc唯一真正的问题。

答案 7 :(得分:1)

我遇到了问题。配置是操作系统:win7(64); IDE:vs2013;调试(Win32)。
当我的realloc由于内存而返回null时。我有两个解决方案:

1.更改项目的属性,以启用大地址 2.将我的解决方案平台从Win32更改为x64。