假设我有一个类似以下的程序
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc < 2) return 1;
long buflen = atol(argv[1]);
char *buf = malloc(buflen);
fread(buf, 1, buflen, stdin);
// Do stuff with buf
free(buf);
return 0;
}
这些程序通常具有更复杂的清理代码,通常包括对free
的多次调用,有时还会标记甚至用于错误处理的清理函数。
我的问题是:free(buf)
到底是否真的有必要?我的理解是,当程序退出时,内核会自动清理不同内存,但如果是这种情况,为什么在代码结尾处释放这样一个常见的模式呢?
BusyBox提供了一个编译选项,可以在执行结束时禁用自由呼叫。如果这不是问题,那么为什么有人会禁用该选项?纯粹是因为像Valgrind这样的程序在分配的内存没有被释放时会检测到内存泄漏吗?
答案 0 :(得分:4)
其实,绝对如此?在现代操作系统上,没有。在一些环境中,是的。
清理您分配的所有内容总是一个很好的计划,因为这样可以非常轻松地扫描内存泄漏。如果您在退出之前有未完成的分配,则会发生泄漏。如果您没有free
因为操作系统为您做了事情,那么您不知道这是错误还是预期的行为。
你也假设来检查任何可能返回它们的函数的错误,例如fread
,但你没有,所以你已经牢牢地处于危险区域这里。这个任务关键代码是否会崩溃坏事发生?如果是这样,你会想要完全按照这本书做的一切。
正如让 - 弗朗索瓦指出这个琐碎的代码组成的方式是一个坏的例子。大多数程序看起来更像这样:
void do_stuff_with_buf(char* arg) {
long buflen = atol(arg);
char *buf = malloc(buflen);
fread(buf, 1, buflen, stdin);
// Do stuff with buf
free(buf);
}
int main(int argc, char *argv[]) {
if (argc < 2)
return 1;
do_stuff_with_buf(argv[1])
return 0;
}
这里应该更明显的是do_stuff_with_buf
函数应该自行清理,它不能依赖于退出程序来释放资源。如果多次调用该函数,则不应泄漏内存,这只是草率并且可能导致严重问题。一个失控的分配可能导致像臭名昭着的Linux“OOM杀手”之类的东西出现并进行谋杀狂欢以释放一些记忆,这通常只能导致混乱和混乱。