免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 7374 | 回复: 22
打印 上一主题 下一主题

[C] 这段代码中的malloc会不会造成内存泄露?如果会怎么解决? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-12-08 22:31 |只看该作者 |倒序浏览

  1. /*        prompting shell version 1
  2. *                Prompts for the command and its arguments.
  3. *                Builds the argument vector for the call to execvp.
  4. *                Uses execvp(), and never returns.
  5. */

  6. #include        <stdio.h>
  7. #include        <signal.h>
  8. #include        <string.h>

  9. #define        MAXARGS                20                                /* cmdline args        */
  10. #define        ARGLEN                100                                /* token length        */

  11. int main()
  12. {
  13.         char        *arglist[MAXARGS+1];                /* an array of ptrs        */
  14.         int        numargs;                        /* index into array        */
  15.         char        argbuf[ARGLEN];                        /* read stuff here        */
  16.         char        *makestring();                        /* malloc etc                */

  17.         numargs = 0;
  18.         while ( numargs < MAXARGS )
  19.         {                                       
  20.                 printf("Arg[%d]? ", numargs);
  21.                 if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
  22.                         arglist[numargs++] = makestring(argbuf);
  23.                 else
  24.                 {
  25.                         if ( numargs > 0 ){                /* any args?        */
  26.                                 arglist[numargs]=NULL;        /* close list        */
  27.                                 execute( arglist );        /* do it        */
  28.                                 numargs = 0;                /* and reset        */
  29.                         }
  30.                 }
  31.         }
  32.         return 0;
  33. }

  34. int execute( char *arglist[] )
  35. /*
  36. *        use execvp to do it
  37. */
  38. {
  39.         execvp(arglist[0], arglist);                /* do it */
  40.         perror("execvp failed");
  41.         exit(1);
  42. }

  43. char * makestring( char *buf )
  44. /*
  45. * trim off newline and create storage for the string
  46. */
  47. {
  48.         char        *cp, *malloc();

  49.         buf[strlen(buf)-1] = '\0';                /* trim newline        */
  50.         cp = malloc( strlen(buf)+1 );                /* get memory        */
  51.                 /*  这里向内存申请分配了内存,可是整个程序都没有 free 的调用,不知道会不会造成内存泄露? */
  52.         if ( cp == NULL ){                        /* or die        */
  53.                 fprintf(stderr,"no memory\n");
  54.                 exit(1);
  55.         }
  56.         strcpy(cp, buf);                /* copy chars        */
  57.         return cp;                        /* return ptr        */
  58. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2008-12-08 23:05 |只看该作者
不会,因为exec系列的函数会使用新的程序替换掉之前进程中的堆空间。所以不会造成内存泄漏。

论坛徽章:
0
3 [报告]
发表于 2008-12-08 23:12 |只看该作者

回复 #2 scutan 的帖子

听上去很有道理

论坛徽章:
0
4 [报告]
发表于 2008-12-08 23:28 |只看该作者
原帖由 雨过白鹭洲 于 2008-12-8 23:12 发表
听上去很有道理


APUE2上面的
The process ID does not change across an exec, because a new process is not created; exec merely replaces the current processits text, data, heap, and stack segmentswith a brand new program from disk.


不过我觉得有空还是可以测试一下,比如说先malloc一个很大的内存,然后再exec,再看该程序是否占用了那么多的内存。

论坛徽章:
0
5 [报告]
发表于 2008-12-09 01:25 |只看该作者

回复 #4 scutan 的帖子

查man手册:

execve() does not return on success, and the text, data, bss, and stack
       of the calling process are overwritten by that of the  program  loaded.
       The  program  invoked  inherits the calling process's PID, and any open
       file descriptors that are not set to close on exec.  Signals pending on
       the  calling  process are cleared.  Any signals set to be caught by the
       calling process are reset to their default behaviour.  The SIGCHLD sig-
       nal (when set to SIG_IGN) may or may not be reset to SIG_DFL.

没看到heap。

但是,通过在exec前加sleep语句试了下,在执行exec前,内存是used了,exec执行对应命令后,如 /bin/ls, 那么内存会回来。

所以认为没问题。

论坛徽章:
0
6 [报告]
发表于 2008-12-09 08:58 |只看该作者
原帖由 scutan 于 2008-12-8 23:05 发表
不会,因为exec系列的函数会使用新的程序替换掉之前进程中的堆空间。所以不会造成内存泄漏。

那么以前的栈内存到哪里去了?被回收了么?

论坛徽章:
0
7 [报告]
发表于 2008-12-09 10:14 |只看该作者
简单修改了一下。

  1. /*        prompting shell version 1
  2. *        *                Prompts for the command and its arguments.
  3. *        *                Builds the argument vector for the call to execvp.
  4. *        *                Uses execvp(), and never returns.
  5. *        */

  6. #include        <stdio.h>
  7. #include        <signal.h>
  8. #include        <unistd.h>
  9. #include        <stdlib.h>
  10. #include        <string.h>

  11. #define        MAXARGS                2                                /* cmdline args        */
  12. #define        ARGLEN                100                                /* token length        */


  13. int execute( char *arglist[] );

  14. int main()
  15. {
  16.     char        *arglist[MAXARGS+1];                /* an array of ptrs        */
  17.     int        numargs;                        /* index into array        */
  18.     char        argbuf[ARGLEN];                        /* read stuff here        */
  19.     char        *makestring();                        /* malloc etc                */

  20.     numargs = 0;
  21.     while ( numargs < MAXARGS )
  22.     {
  23.         printf("Arg[%d]? ", numargs);
  24.         if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
  25.             arglist[numargs++] = makestring(argbuf);
  26.         else
  27.         {
  28.             if ( numargs > 0 ){                /* any args?        */
  29.                 arglist[numargs]=NULL;        /* close list        */
  30.                 execute( arglist );        /* do it        */
  31.                 numargs = 0;                /* and reset        */
  32.             }
  33.         }
  34.     }
  35.     return 0;
  36. }

  37. int execute( char *arglist[] )
  38.     /*
  39.      * *        use execvp to do it
  40.      * */
  41. {
  42.             execvp(arglist[0], arglist);                /* do it */
  43.                     perror("execvp failed");
  44.                             exit(1);
  45. }

  46. char * makestring( char *buf )
  47.     /*
  48.      * * trim off newline and create storage for the string
  49.      * */
  50. {
  51.     char        *cp;

  52.     buf[strlen(buf)-1] = '\0';                /* trim newline        */
  53.     cp = malloc( strlen(buf)+1 );                /* get memory        */
  54.     if ( cp == NULL ){                        /* or die        */
  55.         fprintf(stderr,"no memory\n");
  56.         exit(1);
  57.     }
  58.     strcpy(cp, buf);                /* copy chars        */
  59.     return cp;                        /* return ptr        */
  60. }
复制代码



  1. [jimmy@local memory]$ valgrind --tool=memcheck -v --leak-check=yes ./test_shell
  2. ==7138== Memcheck, a memory error detector for x86-linux.
  3. ==7138== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward et al.
  4. ==7138== Using valgrind-2.2.0, a program supervision framework for x86-linux.
  5. ==7138== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward et al.
  6. ==7138== Valgrind library directory: /usr/lib/valgrind
  7. ==7138== Command line
  8. ==7138==    ./test_shell
  9. ==7138== Startup, with flags:
  10. ==7138==    --tool=memcheck
  11. ==7138==    -v
  12. ==7138==    --leak-check=yes
  13. ==7138== Contents of /proc/version:
  14. ==7138==   Linux version 2.6.9-22.EL ([email]bhcompile@porky.build.redhat.com[/email]) (gcc version 3.4.4 20050721 (Red Hat 3.4.4-2)) #1 Mon Sep 19 18:20:28 EDT 2005
  15. ==7138== Reading syms from /home/jimmy/learn/memory/test_shell (0x8048000)
  16. ==7138==    object doesn't have any debug info
  17. ==7138== Reading syms from /lib/ld-2.3.4.so (0x1B8E4000)
  18. ==7138==    object doesn't have any debug info
  19. ==7138== Reading syms from /usr/lib/valgrind/stage2 (0xB0000000)
  20. ==7138== Reading syms from /lib/ld-2.3.4.so (0xB1000000)
  21. ==7138==    object doesn't have any debug info
  22. ==7138== Reading syms from /usr/lib/valgrind/vgskin_memcheck.so (0xB7C96000)
  23. ==7138== Reading syms from /lib/tls/libc-2.3.4.so (0xB7EBF000)
  24. ==7138==    object doesn't have any debug info
  25. ==7138== Reading syms from /lib/libdl-2.3.4.so (0xB7FEA000)
  26. ==7138==    object doesn't have any debug info
  27. ==7138== Reading suppressions file: /usr/lib/valgrind/default.supp
  28. ==7138== REDIRECT soname:libc.so.6(__GI___errno_location) to soname:libpthread.so.0(__errno_location)
  29. ==7138== REDIRECT soname:libc.so.6(__errno_location) to soname:libpthread.so.0(__errno_location)
  30. ==7138== REDIRECT soname:libc.so.6(__GI___h_errno_location) to soname:libpthread.so.0(__h_errno_location)
  31. ==7138== REDIRECT soname:libc.so.6(__h_errno_location) to soname:libpthread.so.0(__h_errno_location)
  32. ==7138== REDIRECT soname:libc.so.6(__GI___res_state) to soname:libpthread.so.0(__res_state)
  33. ==7138== REDIRECT soname:libc.so.6(__res_state) to soname:libpthread.so.0(__res_state)
  34. ==7138== REDIRECT soname:libc.so.6(stpcpy) to *vgpreload_memcheck.so*(stpcpy)
  35. ==7138== REDIRECT soname:libc.so.6(strnlen) to *vgpreload_memcheck.so*(strnlen)
  36. ==7138== REDIRECT soname:ld-linux.so.2(stpcpy) to *vgpreload_memcheck.so*(stpcpy)
  37. ==7138== REDIRECT soname:ld-linux.so.2(strchr) to *vgpreload_memcheck.so*(strchr)
  38. ==7138==
  39. ==7138== Reading syms from /usr/lib/valgrind/vg_inject.so (0x1B8FC000)
  40. ==7138== Reading syms from /usr/lib/valgrind/vgpreload_memcheck.so (0x1B901000)
  41. ==7138== TRANSLATE: 0x1B8F5F00 redirected to 0x1B904100
  42. ==7138== Reading syms from /lib/tls/libc-2.3.4.so (0x875000)
  43. ==7138==    object doesn't have any debug info
  44. ==7138== TRANSLATE: 0x1B8E47A0 redirected to 0x52BFF040
  45. Arg[0]? hello
  46. ==7138== TRANSLATE: 0x8D8F00 redirected to 0x1B9048F8
  47. Arg[1]? hello
  48. ==7138== TRANSLATE: 0x8D6E30 redirected to 0x1B904E24
  49. ==7138==
  50. ==7138== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
  51. --7138--
  52. --7138-- supp:   12 dl_relocate_object/dl_main
  53. ==7138== malloc/free: in use at exit: 12 bytes in 2 blocks.
  54. ==7138== malloc/free: 2 allocs, 0 frees, 12 bytes allocated.
  55. ==7138==
  56. ==7138== searching for pointers to 2 not-freed blocks.
  57. ==7138== checked 1373240 bytes.
  58. ==7138==
  59. ==7138== [color=Red]12 bytes in 2 blocks are definitely lost in loss record 1 of 1[/color]
  60. ==7138==    at 0x1B904984: malloc (vg_replace_malloc.c:131)
  61. ==7138==    by 0x8048675: makestring (in /home/jimmy/learn/memory/test_shell)
  62. ==7138==    by 0x80485D3: main (in /home/jimmy/learn/memory/test_shell)
  63. ==7138==
  64. ==7138== LEAK SUMMARY:
  65. ==7138==    definitely lost: 12 bytes in 2 blocks.
  66. ==7138==    possibly lost:   0 bytes in 0 blocks.
  67. ==7138==    still reachable: 0 bytes in 0 blocks.
  68. ==7138==         suppressed: 0 bytes in 0 blocks.
  69. ==7138== Reachable blocks (those to which a pointer was found) are not shown.
  70. ==7138== To see them, rerun with: --show-reachable=yes
  71. --7138--     TT/TC: 0 tc sectors discarded.
  72. --7138--            2209 tt_fast misses.
  73. --7138-- translate: new     2067 (36681 -> 485142; ratio 132:10)
  74. --7138--            discard 2 (59 -> 840; ratio 142:10).
  75. --7138-- chainings: 1306 chainings, 3 unchainings.
  76. --7138--  dispatch: 0 jumps (bb entries); of them 4627 (462700%) unchained.
  77. --7138--            24/2274 major/minor sched events.
  78. --7138-- reg-alloc: 474 t-req-spill, 90449+3948 orig+spill uis,
  79. --7138--            11433 total-reg-rank
  80. --7138--    sanity: 22 cheap, 1 expensive checks.
  81. --7138--    ccalls: 7810 C calls, 54% saves+restores avoided (25038 bytes)
  82. --7138--            10348 args, avg 0.87 setup instrs each (2658 bytes)
  83. --7138--            0% clear the stack (23325 bytes)
  84. --7138--            3535 retvals, 30% of reg-reg movs avoided (2056 bytes)
复制代码

[ 本帖最后由 futuregod 于 2008-12-9 10:20 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2008-12-09 10:21 |只看该作者
结果表明,有memory leak

论坛徽章:
0
9 [报告]
发表于 2008-12-09 10:45 |只看该作者
原帖由 futuregod 于 2008-12-9 10:21 发表
结果表明,有memory leak


看内核源代码的话,确实是会回收的。

exec->sys_execve->do_execve
在do_execve中会新创建一个mm_struct结构体。
然后再调用search_binary_handler->load_elf_binary
在 load_elf_binary 中再调用 flush_old_exec,就在这个函数中释放分配给进程的内存描述符,所有的线性区以及所有的页框,并清除进程的页表。
既然页表都没有了,以前所分配的空间自然也就释放了。

论坛徽章:
0
10 [报告]
发表于 2008-12-09 11:15 |只看该作者
狠! kernel都分析了,那块我不懂了。 但是valgrid 不会无故报错吧。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP