由异常终止程序引起的C潜在内存泄漏

时间:2017-03-03 02:21:50

标签: c memory-leaks malloc free

Windows和Linux。

当我在我的C程序中分配内存时,良好的编码要求我在程序结束前释放内存。

假设如下:

int main (int argc, char *argv[]) {
    char *f_name;
    FILE *i_file;

    f_name = malloc(some_amount);
    // put something in f_name */
    i_file = fopen(f_name, "r");
    if (i_file == NULL) {
        perror("Error opening file.");
        exit(EXIT_FAILURE);
    }
    free(f_name);
    return EXIT_SUCCESS;
}

如果程序在我调用" free"之前终止,操作系统会在程序退出时恢复任何未释放的内存吗?或者我是否会从系统重启之前蚕食我的3Gb左右可用内存?

谢谢,Mark。

4 个答案:

答案 0 :(得分:1)

您不必担心Windows和Linux等流行的操作系统。

当进程终止时,虚拟内存不再存在。因此,在进程终止后,它不可能泄漏。

物理内存始终属于要分配的操作系统,无论您的进程是否仍在运行。 (除非你锁定你的分配,在这种情况下,当相应的虚拟内存映射被销毁时,无论如何都会在进程终止时停止锁定它。)

有一些资源没有被清理(比如某些类型的共享内存),但这很奇特。

当您调用malloc时,通常只保留后备存储(本质上是RAM +交换)并创建虚拟内存映射(基本上是免费的)。当您第一次写入该虚拟内存映射时,内存(RAM)的物理页面会映射到它中以“后退”它。 RAM总是属于要使用的操作系统,如果它认为明智,操作系统会将RAM重新用于其他目的。

当进程终止时,其地址空间不再存在。这意味着任何虚拟内存映射或预留都会消失。当虚拟内存映射消失时,非共享物理页面的使用计数将降至零,从而使这些物理内存页面免费。

值得详细了解这一点,因为如果您不了解幕后发生的情况,您可以轻松得出有关边缘案例的错误结论。此外,这将为您提供一个框架,用于插入文件映射,内存过量使用和共享内存等概念。

答案 1 :(得分:0)

操作系统回收内存。

某些程序(如网络服务器)从不打算退出,只是继续运行并提供请求。他们在技术上分配的内存不需要返回。

答案 2 :(得分:0)

在您的示例中,使用此分支确实会导致内存泄漏:

f_name = malloc(some_amount);
// put something in f_name */
i_file = fopen(f_name, "r");
if (i_file == NULL) {
    perror("Error opening file.");
    exit(EXIT_FAILURE);            // <--- f_name leaks here!
}

它只是一次性泄漏,在程序的整个生命周期中都不会经常发生,常见的操作系统会在终止时清理泄漏的内存。它不太可能成为影响系统性能的问题,但是它将成为Valgrind等仪器突出显示的诊断,因此对于调试来说,它是明智的。 <{1}}之前的free(f_name);

该终止不被视为异常,因为它是由exit(EXIT_FAILURE);的呼叫引起的。尽管如此,调用exit或发出信号引起的异常终止可能会在此泄漏的基础上复合。

  

当程序退出时OS会恢复任何未释放的内存吗?

在C标准中没有要求存在操作系统,更不用说恢复未释放的内存了。一些极简主义操作系统可能会在您之后清理。同样,如果您的程序在脚本环境(即CGI)中运行,或者它被刻入芯片中(在这种情况下您可能不希望程序终止),那么您可能会在以后遇到问题。

答案 3 :(得分:-3)

实际上,当流程终止时,程序的内存分配会自动释放。但是,如果函数调用在该函数的代码块中的free()delete调用之前收到异常,则除非被智能引用,否则不会释放内存指针或某种对象。分配内存自动释放的一个推荐选项是使用std::shared_ptr,如下所示:

void BadFunction(){
    char *someMemory = (char *)malloc(1024);
    DoSomethingThatMakesAnException();
    delete someMemory;// This never gets called!
}

void GoodFunction(){
    std::shared_ptr<char> someMemory = std::shared_ptr<char>((char *)malloc(1024));
    DoSomethingThatMakesAnException();
    // someMemory is freed automatically, even on exception!
}