总是检查malloc的内存?

我经常抓住自己做以下事情(在非关键组件中):

some_small_struct *ptr=(some_small_struct *) malloc(sizeof(some_small_struct)); ptr->some_member= ...; 

总之,我为一个小结构分配动态内存,我直接使用它而不检查malloc指针。 我知道程序总是有可能得不到它所要求的内存(呃!)但请考虑以下内容:

如果程序甚至无法为堆中的小型结构获取一些内存,那么可能会出现更大的问题并且它毕竟无关紧要。

此外,如果处理空指针会加剧不稳定的情况呢? (例如,尝试记录条件会调用更多不存在的资源等)

我的推理是否合理(足够)?

更新

  1. 调试时“safe_malloc”函数非常有用,否则可能会有用
  2. +X访问可以隐藏NULL指针的根本原因
  3. 在Linux上,“乐观内存分配”可以影响loom OOM(Out-Of-Memory)条件

取决于平台。 例如,在Linux上(默认情况下)检查NULL没有多大意义:

http://linux.die.net/man/3/malloc

默认情况下,Linux遵循乐观的内存分配策略。 这意味着当malloc()返回非NULL时,无法保证内存确实可用。 这是一个非常糟糕的错误。 如果事实certificate系统内存不足,那么一个或多个进程将被臭名昭着的OOM杀手杀死。

在C的情况下,它取决于平台。 如果你是一个内存非常少的嵌入式平台,那么你应该检查一下,如果它确实失败你会做什么更难说。 在具有虚拟内存的现代32位操作系统上,系统可能会在承认内存不足之前无响应并崩溃。 在这种情况下,对malloc的调用永远不会返回,因此检查其值的实用程序变得没有实际意义。

在C ++的情况下,您应该使用new而不是malloc,在这种情况下,将在耗尽时引发exception,因此检查返回值没有意义。

我会说不。使用NULL指针会导致程序崩溃(可能)。
但是检测它并做一些智能的事情就可以了,你可以从低内存情况中恢复过来。

如果您正在执行大型操作,请设置一些全局错误标志并开始展开堆栈并释放资源。 希望这些资源中的一个或多个将成为您的记忆力,您的应用程序将恢复正常。

这当然是一个C问题,并在exception和RAII的帮助下在C ++中自动处理。
因为new不会返回NULL,所以检查没有意义。

分配可能由于多种原因而失败。 你做(和可以做)的事情部分取决于分配失败。

真正失去记忆是灾难性的。 除非你为此做了一个仔细的计划,否则你可能无能为力。 (例如,您可以预先分配紧急保存和关闭所需的所有资源。)

但许多分配失败与内存不足无关。 碎片可能导致分配失败,因为即使有足够的内存空间,也没有足够的连续空间可用。 这个问题具体说是一个“小结构”,所以这可能和真正的内存不足一样糟糕。 (但是代码是不断变化的。今天的小结构今天可能是一个怪物。如果它太小了,你真的需要堆中的内存还是从堆栈中获取它?)

在multithreading世界中,分配失败通常是瞬态条件。 你的适度分配可能会在这个微秒内失败,但也许一个内存占用线程即将释放一个大缓冲区。 因此,恢复策略可能涉及延迟和重试。

处理分配失败的方式(如果)也取决于应用程序的类型。 如果您正在编写复杂的文档编辑器,并且崩溃意味着丢失用户的工作,那么值得花费更多精力来处理这些失败。 如果您的应用程序是事务性的,并且每个更改都会逐步应用于持久存储,那么崩溃对用户来说只是一个小小的不便。 即便如此,也应考虑采伐。 如果您的应用程序经常出现分配失败,那么您可能有一个错误,并且您需要日志来了解它并跟踪它。

最后,你必须考虑测试。 分配失败很少,因此在您的测试中执行恢复代码的可能性非常小 – 除非您已采取措施通过人为强制失败来确保测试覆盖率。 如果您不打算测试您的恢复代码,那么可能不值得编写它。

至少我会在那里放置一个assert(ptr != NULL) ,这样你就会得到一个有意义的错误。

此外,如果处理空指针会加剧不稳定的情况呢?

我不明白为什么它会加剧局势。
无论如何,在编写windows ptr-> some_member的代码时会抛出访问冲突,所以你会立即看到问题,因此我认为没有理由检查返回值,除非你的程序有机会释放内存。 对于不能以良好方式处理空指针的平台(抛出exception),忽略这些点是危险的。

假设您在Linux / MaxOs / Windows或其他虚拟内存系统上运行,那么…从malloc检查返回值的唯一原因是,您是否有一个释放足够内存以允许程序继续运行的策略。 信息性消息将有助于诊断问题,但前提是您的程序导致内存不足的情况。 通常它不是你的程序,你的程序可以做的唯一帮助就是尽快退出。

 assert(ptr != NULL); 

会做所有这些事情。 我通常的策略是在malloc周围有一个包含它的层。

 void *my_malloc(size_t size) { void *ptr = malloc ( size ); assert(ptr != NULL); return *ptr; } 

然后你调用my_malloc而不是malloc。 在开发过程中,我使用了一个有助于调试的内存分配库。 之后,如果内存不足 – 我收到一条消息。

是的,没有足够的记忆,几乎可以certificate其他失败即将到来。 但是你有多确定在分配失败和最终崩溃之间不会出现损坏的输出?

每次进行编辑时,您对每个程序的确定程度。

抓住你的错误,这样你就可以知道你按时崩溃了。

可以在启动时分配一大块内存,当你遇到内存不足的情况时可以释放它并使用它来优雅地关闭。

我一直觉得处理malloc或任何其他系统调用的返回是非常重要和最好的。 虽然在现代系统中(除了嵌入式系统),但这是一种罕见的情况,除非你的代码使用太多内存,否则它总是更安全。

在系统调用失败后继续执行代码可能会导致损坏,崩溃以及除了使程序看起来不好之外的其他问题。

此外,在linux中,分配给进程的内存是有限的。 尝试在一个进程中创建1000个线程并在每个线程中分配一些内存,然后您可以轻松地模拟低内存条件。 🙂

总是更好地检查sys调用返回值!