繁体   English   中英

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

[英]Wrapping calls to malloc()/realloc()… is this a good idea?

对于赋值,我需要分配一个动态缓冲区,使用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;
}

或者这是一个坏主意?

它的形式呈现一个坏主意,因为在比分配写一个简单的程序什么,你想要做的事更有用的/不是想逃出来优美。 所以最好不要养成坏习惯。 这并不是说分配的包装本身是坏的(集中式错误处理可能是一件好事),只是你不检查返回值的包装器(例如,根本没有返回的包装器)失败)是一个坏主意,除非你提供了一些允许代码挂钩到纾困逻辑的机制。

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

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

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

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

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

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

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__)

编辑:正如其他人提到的,对于经验丰富的程序员来说,这不是一个好习惯,但对于一个有困难的初学者,即使在“快乐”情况下跟踪程序流程也没有问题。

我是否应该在我的C代码中检测OOM(内存不足)错误?

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

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

malloc在现代系统上出现故障的原因有很多:

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

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

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

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

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

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

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

具有大虚拟地址空间的现代系统将永远不会mallocrealloc分开(void*)0 ,如果参数是伪造的,也许。 你会遇到很多问题,很久以后当你的系统开始疯狂交换甚至用完交换时。

所以不,不检查这些功能的返回,这没有多大意义。 相反,使用断言检查malloc的参数是否为0 (对于realloc如果两者同时为0 ),那么问题不在于mallocrealloc而在于你调用它们的方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM