C 当程序遇到错误并在不同位置退出时,如何释放错误分配的内存?



我正在努力想出一种干净的方法来处理C中分配的内存。假设我有这样的东西:

void function(int arg) {
char *foo;
foo = (char *)malloc(sizeof(char) * 100);
int i = func1(arg, &foo);
char *bar;
bar = (char *)malloc(sizeof(char) * 100);
int j = func2(&bar);
free(foo);
free(bar);
}

我的问题是func1func2可能会遇到错误和exit(1),所以当这种情况发生时,我需要释放foobar

如果func1遇到错误,我只需要调用free(foo)就可以了。但如果func2遇到错误,我不能只调用free(bar),因为我还需要释放foo。这可能会变得非常复杂,我觉得这不是处理记忆的正确方法。

我是不是遗漏了什么?如果有人能给我指明正确的方向,那就太棒了。谢谢

如果函数调用exit,则根本不必清理内存使用情况,操作系统将释放它。但是,如果您需要释放其他资源(例如,锁定文件、清理临时文件…),那么您可以使用atexit函数,或者如果您使用gnu-libc,则使用on_exit函数来完成这项工作。

如果func1()func2()在某种情况下要调用exit(1),则不必担心为foobar释放内存,因为一旦进程退出,操作系统通常会进行清理。

只要在正常执行过程中在正确的时间(在退出function之前)free,就不会出现内存泄漏。

我认为有一种简单的方法可以解决这个问题。

在分配资源时,只需在整个程序中维护一个allocCode,如下所示。有几个关键点需要记住。首先,不要在switch案例中使用break语句。每成功分配一次资源,就增加allocCode。对于添加的每一个资源,您都应该在顶部的交换机中添加一个case,并使用一个更高的数字。因此,调用函数freeResourceBeforeExit()将按正确的顺序释放所有资源。请记住,由于没有中断,开关箱将在正确的位置进入,并释放其入口点以下的所有资源。

我将编写psuedo代码。

int allocCode = 0;
int freeResourceBeforeExit()
{
switch(allocCode)
{
case 4:
free(resource3);
case 3:
free(resource2);
case 2:
free(resource1);
case 1:
free(resource0);
}
exit(0);
}

int main()
{
...
resource0 = malloc(10);
allocCode++;
func1();
...
resource1 = malloc(100);
allocCode++;
func2();
...
resource2 = malloc(1000);
allocCode++;
...
func3();
...
resource3 = malloc(10000);
allocCode++;
func4();
... 
so on..
}

希望这能有所帮助!

如果将工作分为几个部分,那么管理资源会容易得多。

void part1(int arg) {
  char *foo;
  foo = (char *)malloc(sizeof(char) * 100);
  int i = func1(arg, &foo);
free(foo);
}
void part2(void) {
  char *bar;
  bar = (char *)malloc(sizeof(char) * 100);
  int j = func2(&bar);
  free(bar);
}
void function(int arg) {
part1(arg);
part2();
}

现在,如果需要,每个部件都可以在退出前free其参数。

原则上,可以安装一个具有atexit的处理程序,该处理程序知道如何释放缓冲区。由于func1调用exit,将调用该处理程序。使用起来不太愉快——处理程序不带参数,这意味着您需要使用全局变量(或局部静态变量)来存储需要释放的东西。它不能被注销,这意味着你需要将这些全局设置为null(或其他一些特殊值),以表明你自己已经释放了资源,但处理程序仍然会被调用。通常,您会使用atexit处理程序作为挂起自己的资源清理框架的"钩子"。

在实践中,对于一些malloced缓冲区来说,这通常太麻烦了,因为当程序退出时,功能齐全的操作系统无论如何都会释放进程保留的所有内存。

在退出之前释放内存甚至可能代价高昂——为了用free释放每个分配,内存将被触摸,这意味着它需要从主内存甚至从交换中拖到缓存中。对于大量可能需要一段时间的小额拨款。当操作系统为你做这件事时,它只是为进程取消映射内存映射,并开始在未来将该地址空间/内存/交换空间重新用于其他事情。清理有好处(例如,它使代码更容易重复使用,使真正的泄漏更容易发现),但也有成本。

顺便说一句,函数func1在出错时调用exit是相当反社会的,因为正如您所发现的,它限制了函数的用户。即使他们认为他们的程序可以/应该在func1失败的情况下继续进行,他们也无法恢复。func1实际上已经宣布,这对该项目来说太重要了,甚至不能梦想在没有结果的情况下继续下去。是的,GMP,我指的是你。

处理它的一种方法:

void function() {
int size = 100;
char bar[size];
char foo[size];
// do stuff
//compiler frees bar and foo for you
}

相关内容

  • 没有找到相关文章