【问题标题】:Exists a way to free memory in atexit or similar without using global variables?是否存在不使用全局变量在 atexit 或类似中释放内存的方法?
【发布时间】:2014-07-24 09:37:07
【问题描述】:

我正在用 C 语言开发一个项目,我需要释放分配的内存并在它退出之前关闭所有打开的文件。

我决定实现一个 clean 函数来完成所有这些工作并使用 atexit 调用它,因为有很多可能的退出场景。

问题是atexit不允许我设置带参数的函数,所以我无法将进程结束时需要释放的指针发送给clean

所以我需要将每个可能需要释放的指针以及可能在程序中保持打开的每个文件都声明为全局变量? (我已经这样做了,但看起来不太好)或者确实存在与atexit 类似的允许发送参数的函数?或者更可能还有另一种我想念的方式?

【问题讨论】:

  • 您只需要一个指向您的内存池的变量。这似乎可以接受。
  • 如果您使用的是现代消费者操作系统,那么所有资源将在您退出时释放。这意味着所有分配的内存将被释放,所有打开的文件将被关闭,等等。
  • 另外,如果你有例如需要在整个过程运行时打开的文件,那么您可能还会在多个地方访问它,这意味着它已经是一个全局变量,或者至少在一个翻译单元中是全局的,然后您可以拥有一个关闭的功能从全局clean_all 函数调用的那个文件。您分配的内存也是如此。
  • 另一方面,如果您只是打开文件然后不关闭它们或分配内存但从未释放它,即使您完成了文件或内存,您也会有资源泄漏,迟早会回来咬你。
  • @this 那样可能没问题,但我正在尝试以最好的方式做,因为这是大学的项目。

标签: c free fclose atexit


【解决方案1】:

在函数内使用静态指针:

#include <stdio.h>
#include <stdlib.h>

void atexit_clean(void *data);

static void clean(void)
{
    atexit_clean(NULL);
}

void atexit_clean(void *data)
{
    static void *x;

    if (data) {
        x = data;
        atexit(clean);
    } else {
        free(x);
    }
}

int main(void)
{
    int *a = malloc(sizeof(int));

    atexit_clean(a);
    return 0;
}

使用单个全局变量的另一种方法:您可以将所有要释放的对象存储在指针数组或链表中,此示例使用realloc(为简洁起见,不检查 (m/re)alloc):

#include <stdio.h>
#include <stdlib.h>

static void **vclean;
static size_t nclean;

void atexit_add(void *data)
{
    vclean = realloc(vclean, sizeof(void *) * (nclean + 1));
    vclean[nclean++] = data;
}

void clean(void)
{
    size_t i;

    for (i = 0; i < nclean; i++) {
        free(vclean[i]);
    }
    free(vclean);
}

int main(void)
{
    int *a, *b, *c;
    double *d;
    int e = 1;

    atexit(clean);
    a = &e;
    b = malloc(sizeof(int));
    atexit_add(b);
    c = malloc(sizeof(int));
    atexit_add(c);
    d = malloc(sizeof(double));
    atexit_add(d);
    return 0;
}

【讨论】:

  • 您应该将atexit(clean_all); 移动到main() 函数的开头。举个实际的例子,在调用 atexit_add() 之间可能存在终止程序的操作。
  • @Kay,这取决于您是想以干净的方式离开还是中止,但总的来说您是对的,已编辑。
  • atexit_add() 应该检查realloc() 失败并向调用者返回错误指示。
【解决方案2】:

无法将任何参数传递给atexit(),因此您无法使用全局变量。

当您的程序通过exit() 或从main() 返回正常终止时,它将自动刷新和关闭所有打开的流并(在大多数操作系统下)释放分配的内存。但是,最好在程序终止之前明确清理资源,因为这通常会导致程序更加结构化。 有时编写程序最简洁的方法是退出并将清理工作留给实现。

但请注意,您应该始终检查fclose() 的返回值。请参阅“What are the reasons to check for error on close()?”,了解如果不这样做会发生什么的轶事。

【讨论】:

  • 请注意,C 标准并不要求实现释放分配的内存。事实上,TI-89 系列的一个常见问题是 C 程序在退出前没有清理,而操作系统没有清理,因此重复执行泄漏程序会耗尽计算器上的 RAM。
猜你喜欢
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-13
  • 2021-05-16
  • 2011-02-10
  • 1970-01-01
相关资源
最近更新 更多