包含对malloc()/ realloc()的调用......这是一个好主意吗?

时间:2010-11-29 10:18:52

标签: c

对于赋值,我需要分配一个动态缓冲区,使用malloc()表示初始缓冲区,realloc()根据需要扩展该缓冲区。我使用的每个地方(re | m)alloc(),代码如下所示:

char *buffer = malloc(size);

if (buffer == NULL) {
    perror();
    exit(EXIT_FAILURE);
}

程序只读取文件中的数据并将其输出,所以我想当(re | m)alloc失败时退出程序是个好主意。现在,真正的问题是:

包裹电话是否有益,例如像这样?

void *Malloc(int size) {
    void *buffer = malloc(size);

    if (buffer == NULL) {
        perror();
        exit(EXIT_FAILURE);
    }

    return buffer;
}

或者这是个坏主意?

6 个答案:

答案 0 :(得分:4)

在提供的表单中这是一个坏主意,因为在任何其他而不是为作业编写的琐碎程序中,你想做一些比拯救更有用/更优雅的事情。所以最好不要养成坏习惯。这并不是说分配包装不好本身(集中错误处理可能是件好事),只是你不检查返回值的包装器(例如,在失败时根本没有返回)是一个坏主意,除非你提供了一些允许代码挂钩到纾困逻辑的机制。

如果您确实希望以自己提供的形式进行此操作,我强烈建议您使用比Malloc更明确的名称而不是malloc。像malloc_or_die一样。 : - )

答案 1 :(得分:4)

在大多数情况下,使用空指针的尝试无论如何都会很快崩溃程序,并且它会使调试变得更容易,因为你会得到一个很好的核心转储来沉溺于其中,如果你打电话给exit()

我给出的唯一建议是在分配后尽快取消引用返回的指针,即使只是无偿,这样核心转储可以引导你直接进入错误的malloc调用。

你很少能从内存耗尽中恢复,所以退出通常是正确的做法。但这样做可以使事后更容易。

但是,要明确的是,内存耗尽通常在操作系统被页面交换活动削弱之后很久就会发生。这个策略实际上只对捕捉荒谬的分配很有用,比如因为bug而尝试malloc(a_small_negative_number)。

答案 2 :(得分:3)

在你的情况下,没关系。只记得给出一条过早退出原因的消息,指定行号会很好。有人这样想:

void* malloc2(int size, int line_num){
    void *buffer = malloc(size);
    if (buffer == NULL) {
        printf("ERROR: cannot alloc for line %d\n", line_num);
        perror();
        exit(EXIT_FAILURE);
        }
    return buffer;
};

#define Malloc(n) malloc2((n), __LINE__)
编辑:正如其他人提到的那样,对于经验丰富的程序员来说,这不是一个好的习惯,但对于一个有困难的初学者来说,即使在“快乐”情况下跟踪程序流程也很困难,这是可以的。

答案 3 :(得分:3)

Should I bother detecting OOM (out of memory) errors in my C code?

这是我对类似问题的回答。总而言之,我赞成设计应用程序,以便它们从任何类型的崩溃中恢复,然后将内存不足视为崩溃的原因。

答案 4 :(得分:1)

“检查malloc失败是没有用的,因为过度使用”或“操作系统在malloc失败时已经瘫痪”已经严重过时了。强大的操作系统永远不会过度使用内存,而且历史上不那么强大的操作系统(如Linux)现在可以通过简单的方法来禁用过度使用并防止因内存耗尽而导致操作系统瘫痪 - 只要应用程序尽其所能malloc失败时不要崩溃和烧毁!

现代系统malloc可能失败的原因有很多:

  • 物理资源不足以实例化内存。
  • 虚拟地址空间耗尽,即使有足够的物理内存空闲。这可以在32位机器(或32位用户空间)上轻松实现,并且具有> 4gb ram + swap。
  • 内存碎片。如果您的分配模式非常糟糕,最终可能会有400万个16字节的块,间隔1000个字节,无法满足malloc(1024)调用。

如何处理内存耗尽取决于程序的性质。

当然,从整个系统的健康状况来看,你的程序死了很好。这可以减少资源饥饿,并可能允许其他应用程序继续运行。另一方面,用户将非常沮丧,如果这意味着丢失编辑视频的工作时间,打字纸,起草博客文章,编码等等。或者如果他们的MP3播放器突然死于外面,他们会感到高兴。 -memory意味着他们的磁盘停止颠倒,他们可以回到他们的文字处理器并点击“保存”。

对于OP的原始问题,我强烈建议不要编写因失败而死的malloc包装器,或编写只是假设malloc失败时使用空指针会立即发生段错误的代码。这是一个容易养成的坏习惯,一旦你编写了充满未经检查的分配的代码,以后在任何鲁棒性都很重要的程序中重用该代码是不可能的。

一个更好的解决方案就是保持对调用函数的返回失败,并让调用函数将其失败返回到其调用函数等,直到你一直回到main或类似的地方,其中你可以写if (failure) exit(1);。这样,代码可以在其他可能实际需要检查错误的情况下立即重用,并采取某种恢复步骤来释放内存,将有价值的数据保存/转储到磁盘等等。

答案 5 :(得分:0)

我认为这是一个坏主意,因为首先检查malloc的返回并不会在现代系统上给你带来太大的影响,因为这会给你提供虚假的安全保障,当你使用这样的电话时,你所有的分配都没问题。

(我假设你是为托管环境而写,而不是嵌入式,独立。)

具有大型虚拟地址空间的现代系统只会永远不会<{1}}从(void*)0malloc返回{}},如果参数是虚假的话。你会遇到很多问题,很久以后当你的系统开始疯狂交换甚至用完交换时。

所以不,不检查这些功能的返回,这没有多大意义。相反,检查realloc针对malloc的参数(对于0,如果两者都是realloc同时使用断言),那么问题不在{{1}内}或0但是你打电话给他们的方式。