突然被老弟问了一个问题,有点蒙蔽,怎么说我也写过 1 年 C 呀,哈哈哈 持续征集C 短小精悍开源代码 完整代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
int
main(int argc, char *argv[])
{
int rc = fork();
if (rc < 0) {
// fork failed; exit
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// child: redirect standard output to a file
close(STDOUT_FILENO);
open("./p4.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
// now exec "wc"...
char *myargs[3];
myargs[0] = strdup("wc"); // program: "wc" (word count)
myargs[1] = strdup("p4.c"); // argument: file to count
myargs[2] = NULL; // marks end of array
execvp(myargs[0], myargs); // runs word count
} else {
// parent goes down this path (original process)
int wc = wait(NULL);
assert(wc >= 0);
}
return 0;
}
子进程里使用了 strdup,没看到内存释放的地方,即使 valgrind 开启了--trace-children=yes 也没有检测到内存泄露,这里是否存在内存泄露?之前有看过 execvp 会替换 fork 之后的子进程的内存空间?不清楚这块内存关系是怎么样的?
我和老弟争执一点如下,我认为如果程序快速执行完退出,不必太过纠结资源释放问题,进程退出了,系统会回收资源,当然好的习惯是不用的时候去 free 掉。针对常驻进程,需要重点关注内存泄露问题。 我认为下面的程序没有内存泄露,即使 valgrind 检测出来:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = (int *)malloc(10 *sizeof(int));
printf("program exit\n");
return 0;
}
1
codehz 2020-03-14 23:33:44 +08:00 via iPhone
程序结束是保证能释放所占用的普通内存的(除了 hugepage 和共享内存)
如果观察到使用内存增多,那么肯定是因为系统缓存了一些东西 fork 到 exec 之间的这段时间所有内存分配都可以简单的无视,不需要考虑释放,exec 之后全都会被吃掉,valgrind 无需跟踪这部分的“泄漏”,除非 exec 失败,通过 exit 退出,这样 valgrind 才能跟踪到泄漏 |
2
52coder OP @codehz 单就这个例子而言:myargs[0] = “ wc”改成这样就不纠结了,我也有点搞不清楚 fork 之后子进程里的机制,execvp 失败退出,避免走到其它不该走的逻辑。例子这里有点不严谨。execvp 成功了不返回,失败了还是要回来,这个函数有点不厚道呀。
|
3
ysc3839 2020-03-14 23:45:31 +08:00
> 我认为如果程序快速执行完退出,不必太过纠结资源释放问题,进程退出了,系统会回收资源
可以认为是对的,比如 Windows 下许多 GUI 程序在启动时会加载图标之类的资源,直到退出也不会释放。包括微软 VS 向导创建的代码也是这样的。 |
4
lance6716 2020-03-14 23:46:38 +08:00
当然是用 gdb 看一下喽
|
5
geelaw 2020-03-15 03:49:29 +08:00 1
如果惟一可能的释放点是进程结束之前,那么是没有必要进行这个操作的,因为“大厦马上就要拆除了,没有必要打扫房间”。
不过你的第一个问题可以用简单的逻辑论证为什么你不需要释放:如果你释放了 strdup 产生的内存,则无法正确调用 execvp (除非你准备静态存储用来放置参数,但这显然无端增加麻烦,系统不会这样设计),因此你无法释放这段内存。 第二个问题取决于你的对内存泄露的定义。 |
6
msg7086 2020-03-15 05:50:34 +08:00
如果你的程序需要继续运行下去,那么你可以在 execvp 后释放 strdup 出来的空间。
execvp 执行成功以后你的进程就被替换了,内存当然全没了。所以最多也只要考虑执行失败的情况。 |