由于内存原因导致realloc失败时如何处理?

发布于 2024-08-16 16:48:34 字数 490 浏览 1 评论 0原文

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

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

如何处理内存不足而不是所有数据为空?

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

Question says it all but here is an example:

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

How can I handle running out of memory and not NULL out all of my data?

edit - let's assume there is something which could be done e.g. free up some memory somewhere or at least tell the user "you can't do that - you're out of memory". Ideally I would like to leave what was allocated there.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

梦明 2024-08-23 16:48:34

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

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

The standard technique is to introduce a new variable to hold the return from realloc. You then only overwrite your input variable if it succeeds:

tmp = realloc(orig, newsize);
if (tmp == NULL)
{
    // could not realloc, but orig still valid
}
else
{
    orig = tmp;
}
非要怀念 2024-08-23 16:48:34

realloc() 失败时采取的策略取决于您的应用程序。这个问题太笼统,无法回答所有可能的情况。

其他一些注意事项:

永远不要这样做:

a = realloc(a, size);

如果 realloc() 失败,您将丢失原始指针,并且 realloc() 不会 free()原来的内存,所以你会得到内存泄漏。相反,应该这样做:

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

我想说的第二点是次要的,可能不是那么重要,但无论如何了解它是件好事:将要分配的内存增加一个因子 f 是好的。假设您首先使用 malloc() n 个字节。然后您需要更多内存,因此您使用 n×f 大小的 realloc() 。那么你需要更多的内存,所以你需要n×f2字节。如果您希望 realloc() 使用前两个内存块的空间,则需要确保 n×f2 ≤ n + n×f 。求解这个方程,我们得到f≤ (sqrt(5)+1)/2 = 1.618黄金比例)。大多数时候我使用 1.5 系数。

The strategy about what to do when realloc() fails depends upon your application. The question is too generic to be answered for all possible cases.

Some other notes:

Never do:

a = realloc(a, size);

If realloc() fails, you lose the original pointer, and realloc() does not free() the original memory, so you will get a memory leak. Instead, do:

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

Second point I want to make is minor and may not be that critical, but it's good to know about it anyway: increasing the memory to be allocated by a factor f is good. Let's say you malloc() n bytes first. Then you need more memory, so you realloc() with size n×f. Then you need more memory, so you need n×f2 bytes. If you want realloc() to use the space from the previous two memory blocks, you want to make sure that n×f2 ≤ n + n×f. Solving this equation, we get f≤ (sqrt(5)+1)/2 = 1.618 (the Golden ratio). I use a factor of 1.5 most of the times.

清君侧 2024-08-23 16:48:34

这一主题本质上有两种思想流派

  1. 这是一个有点热门的话题,因为关于检测 OOM 和让函数返回错误代码
  2. 。检测 OOM 并尽快让你的进程崩溃就

我个人而言,我属于第二阵营。除了非常特殊类型的应用程序之外,OOM 是致命时期。诚然,完美编写的代码可以处理 OOM,但很少有人了解如何编写在没有内存的情况下安全的代码。真正去真正去做的人就更少了,因为这几乎不值得付出努力。

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

This is a bit of a hot button topic as there are essentially 2 schools of thought on the subject

  1. Detect the OOM, and having the function return an error code.
  2. Detect the OOM and crash your process as fast as possible

Personally I am in camp #2. Expect for very special types of applications, OOM is fatal period. True, perfectly written code can handle an OOM but so few people understand how to write code that is safe in the face of no memory. Even fewer bother to actually do it because it's almost never worth the effort.

I dislike passing the error code off to the calling function for OOM's because it is the equivalent of telling the caller "I failed and there's nothing you can do about it". Instead I prefer to crash fast so the resulting dump is as instructive as possible.

孤寂小茶 2024-08-23 16:48:34

使用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 */;

The first rule that you shoud follow when working with realloc is not to assign the return value of realloc to the same pointer that you passed to it. This

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

is bad. If realloc fails, it returns null pointer, but it doesn't deallocate the old memory. The above code will null your m->data while the old memory block formerly pointed by m->data will most likely become memory leak (if you have no other references to it).

The return value of realloc should be stored in a separate pointer first

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

Then you can check for success/failure and change the value of m->data in case of success

if (new_data != NULL)
  m->data = new_data;
else
  /* whatever */;
酸甜透明夹心 2024-08-23 16:48:34

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

  • 您请求该内存是有原因的。如果它不可用,那么您的程序的工作是否注定要失败还是可以继续做事?如果是前者,您希望终止程序并显示错误消息;否则,您可以以某种方式显示错误消息并继续。

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

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

    如果

That's entirely your problem! Here are some criteria:

  • You asked for that memory for a reason. If it's not available, is your program's work doomed or can it go on doing stuff? If the former, you want to terminate your program with an error message; otherwise, you can display an error message somehow and go on.

  • Is there a possibility to trade time for space? Could you reply whatever operation you attempted using an algorithm that uses less memory? That sounds like a lot of work but would in effect be a possibility for continuing your program's operation in spite of not having enough memory initially.

  • Would it be wrong for your program to continue limping along without this data and not enough memory? If so, you should terminate with an error message. It is much better to kill your program than to blindly continue processing incorrect data.

美羊羊 2024-08-23 16:48:34
  1. 了解应用程序框架如何处理 OOM。许多人根本无法处理 OOM。大多数时候,框架在没有空闲 RAM 的情况下将无法正常运行,除非它在某个地方非常清楚、明确地表明它可以正常运行。如果框架无法处理 OOM 并且是多线程的(现在很多都是),那么在很多情况下,OOM 将成为进程的结束。即使它不是多线程的,它仍然可能接近崩溃。无论您退出进程还是框架退出可能都是一个有争议的问题;可预测的立即退出可能比在不久的将来某个半随机点崩溃要好一些。

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

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

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

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

当然,严峻的考验是您是否能够通过长时间的正常运行以及罕见的数据损坏、丢失或崩溃来充分满足用户的要求。在某些情况下,具有监控进程的应用程序在崩溃时可以重新启动它是有用的。

关于 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)中的“大多数情况”更改为“很多情况”。

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

  1. Find out how the application framework handles an OOM. Many will simply not handle an OOM. Most of the time a framework will not operate properly in no-free-RAM conditions unless it says very clearly and unambiguously somewhere that it will. If the framework won't handle an OOM and is multithreaded (many are nowadays), an OOM is gonna be the end of the show for the process in a lot of cases. Even if it isn't multithreaded it may still be close to collapse. Whether you exit the process or the framework does may be a moot point; a predictable immediate exit may just be a bit better than a crash out at some semi-random point in the near future.

  2. If you're using a separate special-purpose sub-memory pool (ie not your usual malloc) for a well-defined set of operations that are only constrained in memory use by OOM (ie the current operation is rolled back or aborted cleanly on OOM for the sub-memory pool, not the whole process or main memory pool), and that sub-pool is not also used by the application framework, or if your framework and the WHOLE of the rest of the application is designed to maintain meaningful state and continued operation in no-free-RAM conditions (rare but not unheard of in kernel mode and some types of systems programming) you may be right to return an error code rather than crash the process.

  3. Ideally the bulk of the memory allocations (or even more ideally all the allocations) for a piece of processing should be allocated as soon as possible in processing, ideally before it properly begins, to minimise the problems of data integrity loss and/or amount of rollback coding required if it fails. In practice a lot of the time, to save programming cost and time on projects, to preserve data integrity applications rely on database transactions and requiring the user/support person to detect a GUI crash (or server crash) and restart the app when out of memory errors occur, rather than being written to cope with and rollback on any and all of thousands of potential OOM situations in the best possible ways. Then efforts focus on trying to limit the exposure of the app to overloading situations, which may include additional validation and limits on data size and simultaneous connections and queries.

  4. Even if you check how much memory is reported as available, often other code may alloc or free memory as you do, changing the basis for your memory check and possibly leading to OOM. So checking available free RAM before you alloc is often not a reliable solution to the problem of making sure your application operates within available RAM limits and maintains data integrity enough of the time to satisfy the users.

  5. The best situation to be in is to know how much memory your app requires in all possible cases, including any framework overheads, and to keep that figure within the amount of RAM available to your application, but systems are often so complicated with external dependencies dictating data size so achieving this can be unrealistic.

The acid test of course is are you satisfying the users sufficiently through high up-time, and infrequent data corruption, loss or crashes. In some cases an app having a monitor process to restart it if it crashes is useful.

As regards realloc:

Check the return value from realloc - put it in a temporary variable. Only care if it is NULL if the new size requested was >0. In other cases place it in your non-temporary variable:

eg

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

EDIT

Changed "most cases" to "a lot of cases" in (1).

I recognise that you said to assume that "something can be done" if the memory cannot be allocated. But memory management is a very global consideration (!).

微暖i 2024-08-23 16:48:34

还有另一个细微的错误可能来自 realloc。来自返回 NULL 指针的内存泄漏是众所周知的(但很少偶然发现)。
我的程序偶尔会因 realloc 调用而崩溃。我有一个动态结构,可以使用与此类似的 realloc 自动调整其大小:

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

我犯的错误是不检查 m->max == 0,这释放了内存区域。并从我的 m->data 指针变成了一个陈旧的指针。

我知道这有点偏离主题,但这是我在使用 realloc 时遇到的唯一真正问题。

There's also another subtle error that can come from realloc. The memory leak coming from returned NULL pointer is rather well known (but quite rare to stumble upon).
I had in my program a crash once in a while that came from a realloc call. I had a dynamic structure that adjusted its size automatically with a realloc resembling this one:

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

The error I made was to not check for m->max == 0, which freed the memory area. And made from my m->data pointer a stale one.

I know it's a bit off-topic but this was the only real issue I ever had with realloc.

昨迟人 2024-08-23 16:48:34

我遇到了这个问题。配置是 OS:win7(64);IDE:vs2013;Debug(Win32)。
当我的 realloc 由于内存不足而返回 null 时。我有两种解决方案:

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

I have come across the problem.The configuration is OS:win7(64);IDE:vs2013;Debug(Win32).
When my realloc returned null due to memory in.I have two solutions to it:

1.Change the project's property, to enable LARGE ADDRESSES.
2.Change my solution platform from Win32 to x64.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文