fork vs execvp,子进程中内存泄露? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
52coder

fork vs execvp,子进程中内存泄露?

  •  
  •   52coder 2020 年 3 月 14 日 2296 次点击
    这是一个创建于 2233 天前的主题,其中的信息可能已经有所发展或是发生改变。

    突然被老弟问了一个问题,有点蒙蔽,怎么说我也写过 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; } 
    9 条回复    2020-03-15 15:04:15 +08:00
    codehz
        1
    codehz  
       2020 年 3 月 14 日 via iPhone
    程序结束是保证能释放所占用的普通内存的(除了 hugepage 和共享内存)
    如果观察到使用内存增多,那么肯定是因为系统缓存了一些东西
    fork 到 exec 之间的这段时间所有内存分配都可以简单的无视,不需要考虑释放,exec 之后全都会被吃掉,valgrind 无需跟踪这部分的“泄漏”,除非 exec 失败,通过 exit 退出,这样 valgrind 才能跟踪到泄漏
    52coder
        2
    52coder  
    OP
       2020 年 3 月 14 日
    @codehz 单就这个例子而言:myargs[0] = “ wc”改成这样就不纠结了,我也有点搞不清楚 fork 之后子进程里的机制,execvp 失败退出,避免走到其它不该走的逻辑。例子这里有点不严谨。execvp 成功了不返回,失败了还是要回来,这个函数有点不厚道呀。
    ysc3839
        3
    ysc3839  
       2020 年 3 月 14 日
    > 我认为如果程序快速执行完退出,不必太过纠结资源释放问题,进程退出了,系统会回收资源

    可以认为是对的,比如 Windows 下许多 GUI 程序在启动时会加载图标之类的资源,直到退出也不会释放。包括微软 VS 向导创建的代码也是这样的。
    lance6716
        4
    lance6716  
       2020 年 3 月 14 日
    当然是用 gdb 看一下喽
    geelaw
        5
    geelaw  
       2020 年 3 月 15 日   1
    如果惟一可能的释放点是进程结束之前,那么是没有必要进行这个操作的,因为“大厦马上就要拆除了,没有必要打扫房间”。

    不过你的第一个问题可以用简单的逻辑论证为什么你不需要释放:如果你释放了 strdup 产生的内存,则无法正确调用 execvp (除非你准备静态存储用来放置参数,但这显然无端增加麻烦,系统不会这样设计),因此你无法释放这段内存。

    第二个问题取决于你的对内存泄露的定义。
    msg7086
        6
    msg7086  
       2020 年 3 月 15 日
    如果你的程序需要继续运行下去,那么你可以在 execvp 后释放 strdup 出来的空间。
    execvp 执行成功以后你的进程就被替换了,内存当然全没了。所以最多也只要考虑执行失败的情况。
    52coder
        7
    52coder  
    OP
       2020 年 3 月 15 日
    @msg7086 执行成功以后进程被替换?执行时需要的内存从哪来的?有介绍这方面的文章吗?我觉得应该是你说的这个点。
    msg7086
        8
    msg7086  
       2020 年 3 月 15 日
    @52coder exec 不就是把自身进程替换成目标程序吗。当前进程的代码和内存空间都会被抹平,然后开始执行新的程序,让新的程序来重新申请内存空间。
    比如你这里运行了 exec("wc")以后,你程序的代码和内存都会消失,然后内核把 wc 的代码加载进内存,然后运行 wc 的入口,让 wc 去申请和使用它自己新的内存空间。
    52coder
        9
    52coder  
    OP
       2020 年 3 月 15 日
    @msg7086 学习了,多谢大佬
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2807 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 40ms UTC 12:38 PVG 20:38 LAX 05:38 JFK 08:38
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86