2

I'm struggling to come up with a clean way to handle my allocated memory in C. Suppose I have something like this:

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);
}

My problem is that func1 and func2 may encounter error and exit(1), so I need to free foo and bar when that happens.

If func1 encounters error, I just call free(foo) and I'll be good. But if func2 encounters error, I cannot just call free(bar) since I also need to free foo. This can get really complicated and I feel that this is not the right way to handle memory.

Am I missing anything here? It will be awesome if someone can point me the right direction. Thanks!

4

6 回答 6

3

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

于 2012-09-18T15:01:16.527 回答
2

如果func1()func2()exit(1)在某些情况下调用,您不必担心释放内存,foo或者bar因为操作系统通常会在进程退出后进行清理。

只要您在正常执行过程中free在正确的时间(退出之前),您就可以很好地避免内存泄漏。function

于 2012-09-18T14:57:35.317 回答
0

如果你把你的工作分成几个部分,管理你的资源会容易得多。

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在退出之前使用其参数。

于 2012-09-18T15:38:15.593 回答
0

I think so there can be a one simple approach to this problem.

Just maintain an allocCode throughout your program when allocating resources something like one given below. There are few keypoints to remember. First is that, don't you break statement in your switch case. Increment the allocCode, for every successful allocation of resource. For every resource added, you should add a case in the switch at the top, with one higher number. So calling the function freeResourceBeforeExit() will free all your resources in correct order. Remember that, since there is no break, the switch case will enter at the correct position and free all the resource which are below its entry point.

I will write the psuedo-code.

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..
}

Hope this helps !

于 2012-09-18T15:23:17.903 回答
0

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

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

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

func1顺便说一句,调用错误是函数的反社会行为exit,因为正如您所发现的那样,它对函数的用户施加了限制。即使他们认为他们的程序可以/应该在失败的情况下继续进行,他们也无法恢复func1func1实际上已经宣布该计划太重要了,甚至梦想在没有结果的情况下继续进行。是的,GMP,我的意思是你。

于 2012-09-18T15:53:15.107 回答
-2

一种处理方法:

void function() {
  int size = 100;
  char bar[size];
  char foo[size];

  // do stuff

  //compiler frees bar and foo for you
}
于 2012-09-18T14:54:53.063 回答