C语言忘记释放内存(内存泄漏)

示例

编程的最佳做法是释放已由您自己的代码直接分配的任何内存,或者通过调用内部或外部函数(例如库API之类)来隐式释放任何内存strdup()。无法释放内存可能会导致内存泄漏,这可能会累积到程序(或系统)无法使用的大量浪费的内存中,从而可能导致崩溃或不确定的行为。如果在循环或递归函数中反复发生泄漏,则更有可能发生问题。程序泄漏的风险越长,程序失败的风险就越大。有时问题立即出现;有时甚至数小时甚至数年的持续运行也不会出现问题。内存耗尽故障可能是灾难性的,具体取决于情况。

以下无限循环是一个泄漏示例,该泄漏最终将通过调用getline(),而该函数隐式分配新内存,而不释放该内存,从而耗尽可用内存泄漏。

#include <stdlib.h>

#include <stdio.h>

int main(void)

{

    char *line = NULL;

    size_t size = 0;

    /* The loop below leaks memory as fast as it can */

    for(;;) { 

        getline(&line, &size, stdin); /* New memory implicitly allocated */

        /* <do whatever> */

        line = NULL;

    }

    return 0;

}

相比之下,下面的代码也使用该getline()函数,但是这次,分配的内存已正确释放,避免了泄漏。

#include <stdlib.h>

#include <stdio.h>

int main(void)

{

    char *line = NULL;

    size_t size = 0;

    for(;;) {

        if (getline(&line, &size, stdin) < 0) {

            free(line);

            line = NULL;

            /* Handle failure such as setting flag, breaking out of loop and/or exiting */

        }

        /* <do whatever> */

        free(line);

        line = NULL;

    }

    return 0;

}

内存泄漏并不总是会产生明显的后果,也不一定是功能性问题。尽管“最佳实践”要求在战略要点和条件下严格释放内存,以减少内存占用并降低内存耗尽的风险,但也有例外。例如,如果程序的持续时间和范围受到限制,则分配失败的风险可能被认为太小而不必担心。在那种情况下,绕过显式的重新分配可能被认为是可以接受的。例如,大多数现代操作系统都会在程序终止时自动释放其消耗的所有内存,无论是由于程序故障,系统调用exit(),进程终止还是结束。main()。在即将终止程序时明确释放内存实际上可能是多余的,或者会导致性能下降。

如果没有足够的可用内存,分配可能会失败,并且应该在调用堆栈的适当级别考虑处理失败。getline(),上面显示的,是一个有趣的用例,因为它是一个库函数,它不仅分配留给调用者的内存以释放空间,而且由于多种原因而可能失败,因此必须考虑所有这些因素。因此,使用C API时,阅读文档(手册页)并特别注意错误条件和内存使用情况,并意识到哪个软件层承担释放返回的内存的负担是至关重要的。

另一种常见的内存处理实践是在释放那些指针所引用的内存之后立即将内存指针始终设置为NULL,因此可以随时测试这些指针的有效性(例如,检查NULL /非NULL),因为访问已释放的内存可能会导致严重问题,例如获取垃圾数据(读取操作)或数据损坏(写入操作)和/或程序崩溃。在大多数现代操作系统中,NULL按照C标准的要求,释放内存位置0()是一个NOP(例如,它是无害的)-因此,通过将指针设置为NULL,如果指针是NULL,则没有双重释放内存的风险。传递给free()。请记住,双重释放内存可能会导致非常耗时,令人困惑并且难以诊断故障。

以上是 C语言忘记释放内存(内存泄漏) 的全部内容, 来源链接: utcz.com/z/334573.html

回到顶部