【问题标题】:Should I free allocated memory upon fatal error? [duplicate]我应该在致命错误时释放分配的内存吗? [复制]
【发布时间】:2013-11-08 11:45:38
【问题描述】:

有时诸如库错误之类的事情将不允许我的程序继续运行,例如对SDL_Init 的调用变坏了。我应该尝试释放尽可能多的内存,还是直接退出?我还没有看到任何人们不只是退出的小例子,但我不够聪明,无法阅读 DOOM-3 代码或类似的任何东西。

【问题讨论】:

    标签: c memory free fatal-error quit


    【解决方案1】:

    我不会。如果您的程序由于程序中发生的一些奇异的、无法预料的事情而崩溃,那么尝试释放任何已分配的堆内存甚至可能毫无意义。
    如果可以的话,我认为最好只调用exit (EXIT_FAILURE),然后让操作系统尽可能好地回收你分配的内存。

    但是,我会尝试清理您使用/声称/打开的任何其他资源,这些资源也可能导致泄漏。尽可能多地关闭打开的文件指针,或刷新周围的任何缓冲区。
    除此之外,我想说:把它留给操作系统。您的程序已崩溃或正在崩溃:在无法预料的情况下尝试自行清理可能毫无意义,或者 - 谁知道 - 最终弊大于利。

    当然,如果 "a library errors" 你的意思是:

    MYSQL *connection = mysql_init();
    if (connection == NULL)
    {//connection could not be initiated
        //what to do here?
    }
    

    或者,没有库:

    char **arr_of_strings = malloc(200*sizeof(char *));
    //some code
    arr_of_strings[0] = calloc(150, sizeof(char));
    //some more
    arr_of_strings[120] = calloc(350, sizeof(char));
    if (arr_of_strings == NULL)
    {//ran out of heap memory
        //what do I do here?
    }
    

    所以,基本上:问题在于:您的程序必须做什么,以及您能否轻松找到解决所面临问题的方法。
    例如,如果您正在编写一个 mysql 客户端,而 mysql_init 调用失败,我认为很明显您无法继续。您可以尝试为可能发生这种情况的所有原因提供后备方案,或者您可以直接退出。我会选择后者。
    在第二种情况下,很明显您已经耗尽了堆内存。如果您仍要将这些字符串写入文件,则可以防止此类错误,如下所示:

    int main()
    {
        char **arr_str = malloc(20*sizeof(char *));
        const char *fileName = "output.txt";
        int i, j;
        int alloc_str(char ***str, int offset, int size);
        void write_to_file(const char *string, const char *fileName);
        for(i=0;i<10;++i)
        {
            if (alloc_str(&arr_str, i, 100+i) == -1)
            {
                if (i == 0) exit(EXIT_FAILURE);//this is a bigger problem
                for (j=0;i<i;++j)
                {//write what we have to file, and free the memory
                    if (arr_str[j] != NULL)
                    {
                        write_to_file(arr_str[j], fileName);
                        free(arr_str[j]);
                        arr_str[j] = NULL;
                    }
                    if (alloc_str(&arr_str, i, 100+i) != -1) break;//enough memory freed!
                }
            }
            //assign value to arr_str[i]
        }
        for(i=0;i<10;++i) free(arr_str[i]);
        free(arr_str);
        return 0;
    }
    
    void write_to_file(const char *string, const char *fileName)
    {//woefully inefficient, but you get the idea
        FILE* outFile = fopen(fileName, "a");
        if (outFile == NULL) exit (EXIT_FAILURE);
        fprintf(outFile, "%s\n", string);
        fclose(outFile);
    }
    
    int alloc_str(char ***str, int offset, int size)
    {
        (*str)[offset] = calloc(size, sizeof(char));
        if ((*str)[offset] == NULL) return -1;
        return 0;
    }
    

    在这里,我试图创建一个字符串数组,但是当我用完内存时,我只会将一些字符串写入文件,释放它们占用的内存,然后继续。然后,我可以参考我写入必须从内存中清除的字符串的文件。在这种情况下,我可以确保,尽管它确实会导致一些额外的开销,但我的程序将运行良好。
    但是,在第二种情况下,释放内存是必须的。我必须释放程序继续运行所需的内存,但考虑到所有因素,这很容易解决。

    【讨论】:

    • +1 关于“其他资源”。
    【解决方案2】:

    这取决于。这些天来,操作系统清理了你造成的混乱,但在嵌入式系统上你可能没有那么幸运。但即便如此,仍有一个问题,“那又怎样,我的系统还是坏了。我将重新启动/重新启动/再试一次”

    就我个人而言,我喜欢以这样一种方式安排我的代码,即在退出时,它会检查哪些资源正在使用并释放这些资源。正常退出还是报错都没关系。

    【讨论】:

    • 在出现严重错误后尝试释放资源很容易导致多点异常,从而掩盖问题的原始根源。这对于复杂的多线程应用程序尤其成问题,因为在错误发生时整个进程的状态是未知的。
    • @MartinJames 我认为asker 的意思是可以从返回值中检测到的错误,例如SDL_Init。也只有 C 标签,所以没有例外。
    • 哎呀.. 好的,'函数调用返回的'失败'导致的错误消息的雨':)
    【解决方案3】:

    尽可能多地释放内存并做其他必要的工作(例如日志、备份),而不是直接退出。程序有责任释放它分配的内存。不依赖操作系统,以为程序结束后会释放内存。

    我不久前写了一个内存泄漏检测模块,它要求程序释放分配的内存。如果它不释放内存,模块就不能工作,它无法判断剩下的内存块是否泄漏。

    【讨论】:

    • 这种方法对于复杂的多线程应用程序来说显然是不可能的,因为在错误发生时进程的状态是未知的。如果幸运的话,记录器可能仍会运行足够长的时间,以便在一切崩溃之前输出一些有用的信息。
    猜你喜欢
    • 2018-08-29
    • 1970-01-01
    • 2019-05-25
    • 2017-03-22
    • 2021-05-30
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多