我经常发现自己正在做以下事情(在非关键组件中):
some_small_struct *ptr=(some_small_struct *) malloc(sizeof(some_small_struct));
ptr->some_member= ...;
总之,我为一个小结构分配动态内存,我直接使用它而不检查malloc指针。我知道程序总是有可能无法获得它要求的内存(呃!)但请考虑以下内容:
如果程序甚至无法获得一些小型结构的内存 堆,也许还有更大的问题迫在眉睫,毕竟无关紧要。
此外,如果处理空指针会加剧岌岌可危的情况呢? (例如,尝试记录条件会调用更多不存在的资源等。)
我的推理是否合理(足够)?
更新:
+X
访问可以隐藏NULL指针的根本原因答案 0 :(得分:19)
取决于平台。例如,在Linux上(默认情况下)检查NULL是没有意义的:
http://linux.die.net/man/3/malloc
默认情况下,Linux遵循乐观的内存分配策略。这意味着当malloc()返回非NULL时,无法保证内存确实可用。这是一个非常糟糕的错误。如果事实证明系统内存不足,臭名昭着的OOM杀手就会杀死一个或多个进程。
答案 1 :(得分:11)
在C的情况下,它取决于平台。如果你在一个内存很少的嵌入式平台上,那么你应该检查一下,如果它确实失败你会做什么更难说。在具有虚拟内存的现代32位操作系统上,系统可能会在承认内存不足之前无响应并崩溃。在这种情况下,对malloc的调用永远不会返回,因此检查其值的实用程序变得毫无意义。
对于C ++,你应该使用new而不是malloc,在这种情况下会在耗尽时引发异常,所以检查返回值没有意义。
答案 2 :(得分:7)
我会说不。 使用NULL指针会使程序崩溃(可能) 但是检测它并做一些智能的事情就可以了,你可以从低内存情况中恢复过来。
如果您正在执行大型操作,请设置一些全局错误标志并开始展开堆栈并释放资源。希望这些资源中的一个或多个将成为您的记忆力,您的应用程序将恢复正常。
这当然是一个C问题,并在例外和RAII的帮助下在C ++中自动处理 因为new不会返回NULL,所以检查没有意义。
答案 3 :(得分:7)
分配可能由于多种原因而失败。你做(和可以做)的事情部分取决于分配失败。
真正失去记忆是灾难性的。除非你为此做了一个仔细的计划,否则你可能无能为力。 (例如,您可以预先分配紧急保存和关闭所需的所有资源。)
但许多分配失败与内存不足无关。碎片可能导致分配失败,因为即使有足够的可用内存,也没有足够的连续空间可用。这个问题具体说是一个“小结构”,所以这可能和真正的内存不足一样糟糕。 (但代码是不断变化的。今天的小结构今天可能是一个怪物。如果它太小了,你真的需要堆中的内存还是从堆栈中获取它?)
在多线程世界中,分配失败通常是瞬态条件。你的适度分配可能会失败这个微秒,但也许一个内存占用线程即将释放一个大缓冲区。因此,恢复策略可能涉及延迟和重试。
处理分配失败的方式(如果)也取决于应用程序的类型。如果您正在编写复杂的文档编辑器,并且崩溃意味着丢失用户的工作,那么值得花费更多精力来处理这些失败。如果您的应用程序是事务性的,并且每个更改都会逐步应用于持久存储,那么崩溃只会给用户带来轻微的不便。即便如此,也应考虑采伐。如果您的应用程序经常出现分配失败,那么您可能有一个错误,并且您需要日志来了解它并跟踪它。
最后,你必须考虑测试。分配失败很少,因此在测试中执行恢复代码的可能性非常小 - 除非您已采取措施通过人为强制失败来确保测试覆盖率。如果你不打算测试你的恢复代码,那么可能不值得写它。
答案 4 :(得分:2)
至少我会在那里放一个assert(ptr != NULL)
,这样你就会得到一个有意义的错误。
答案 5 :(得分:2)
此外,如果处理空指针会加剧不稳定的情况呢?
我不明白为什么它会加剧这种情况 无论如何,在编写windows ptr->的代码时,some_member将抛出访问冲突,因此你会立即看到问题,因此我认为没有理由检查返回值,除非你的程序有机会释放内存。 对于没有以良好方式处理空指针的平台(抛出异常),忽略这些点是危险的。
答案 6 :(得分:2)
假设您正在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。在开发过程中,我使用了一个有助于调试的内存分配库。之后如果内存耗尽 - 我收到一条消息。
答案 7 :(得分:1)
是的,没有足够的记忆,几乎可以证明其他失败即将来临。 但你有多确定在分配失败和最终崩溃之间不会出现损坏的输出?
您对每个计划的确定程度,每次时间进行编辑。
抓住您的错误,以便知道您按时崩溃。
答案 8 :(得分:0)
可以在启动时分配一大块内存,当你遇到内存不足的情况时可以释放它并使用它来优雅地关闭。
答案 9 :(得分:0)
我一直觉得处理malloc或任何其他系统调用的返回很重要也是最好的。虽然在现代系统中(除了嵌入式系统),但这是一种罕见的情况,除非你的代码使用太多内存,否则它总是更安全。
在系统调用失败后继续执行代码会导致损坏,崩溃以及除了使程序看起来不好之外的其他问题。
此外,在linux中,分配给进程的内存是有限的。尝试在一个进程中创建1000个线程并在每个线程中分配一些内存,然后您可以轻松地模拟低内存条件。 :)
最好检查sys调用返回值!