免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: korpus
打印 上一主题 下一主题

[C] 线程创建子线程,线程退出时,释放了内存,但是TOP中只看到有一般的内存被释放了 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2014-02-12 22:36 |只看该作者
gcc和操作系统均有可能有内存池。

论坛徽章:
0
12 [报告]
发表于 2014-02-13 08:53 |只看该作者
回复 10# gaojl0728


    就是最奇怪的就是,如果我把LOG_DEBUG("Thread Will Quit");  这行注释掉,top命令显示就是正常的。

论坛徽章:
0
13 [报告]
发表于 2014-02-13 08:55 |只看该作者
回复 9# folklore


    你好,谢谢的你的关注哈。

进程结束,内存是会被回收的,现在是在线程里面。

论坛徽章:
0
14 [报告]
发表于 2014-02-13 09:03 |只看该作者
回复 11# 一只嗡嗡的苍蝇


    你好,谢谢你的关注。
能不能确认这个内存池呢

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
15 [报告]
发表于 2014-02-13 09:55 |只看该作者
上 Valgrind 吧。

论坛徽章:
0
16 [报告]
发表于 2014-02-13 16:18 |只看该作者
本帖最后由 korpus 于 2014-02-13 16:23 编辑

我把代码整理出来了一份可以独立编译  

比较奇怪的是如果注释掉函数 trans_SingleThread  LOG_DEBUG("Thread Will Quit [%ld]", pthread_self());,释放回正常,如果没注释释放就不正常了
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <errno.h>
  6. #include <stdarg.h>
  7. #include <sys/timeb.h>
  8. #include <sys/stat.h>
  9. #include <pthread.h>

  10. typedef enum
  11. {
  12.     LOG_LEVEL_ERROR, // only print ERROR log
  13.     LOG_LEVEL_WARN,  // print ERROR and WARN log
  14.     LOG_LEVEL_INFO,  // print ERROR, WARN and INFO log
  15.     LOG_LEVEL_DEBUG,  // print ERROR, WARN, INFO AND DEBUG log
  16.     LOG_LEVEL_ALL    // print all log, and print full debug log and other informations
  17. }LOG_LEVEL;

  18. static char g_szLogHead[200];
  19. static long g_iSetLogLevel = 3;
  20. static long g_lSetLogSize = 0;
  21. static int g_iLogLevel;
  22. static char g_szLogFile[256]="./test.log";
  23. pthread_mutex_t g_WriteLog = PTHREAD_MUTEX_INITIALIZER;
  24. static char g_szLogPath[128]=".";
  25. static char g_szLogName[128]="test.log";

  26. #define LOG_ERROR       Log_SysInfo(LOG_LEVEL_ERROR,__FILE__,__LINE__),Log_Msg
  27. #define LOG_WARN        Log_SysInfo(LOG_LEVEL_WARN,__FILE__,__LINE__),Log_Msg
  28. #define LOG_INFO        Log_SysInfo(LOG_LEVEL_INFO,__FILE__,__LINE__),Log_Msg
  29. #define LOG_DEBUG       Log_SysInfo(LOG_LEVEL_DEBUG,__FILE__,__LINE__),Log_Msg
  30. #define RT_SUCCESS      0
  31. #define RT_FAILURE      -1

  32. void Log_Check();

  33. long timel_GetCurrentTime()
  34. {
  35.     char szTime[7];
  36.     long lCurTime;
  37.     struct tm *ptime;
  38.     time_t times;
  39.     time(&times);
  40.     ptime = localtime(&times);
  41.     memset(szTime, 0, sizeof(szTime));
  42.     sprintf(szTime, "%02d%02d%02d", ptime->tm_hour, ptime->tm_min, ptime->tm_sec);
  43.     lCurTime = atol(szTime);
  44.     return lCurTime;
  45. }

  46. long timel_GetCurrentDate()
  47. {
  48.     char szDate[9];
  49.     long lDate;
  50.     struct tm *ptm;
  51.     time_t times;
  52.     time(&times);
  53.     ptm = localtime(&times);
  54.     memset(szDate, 0, sizeof(szDate));
  55.     sprintf(szDate, "%d%02d%02d", ptm->tm_year+1900, ptm->tm_mon + 1, ptm->tm_mday);
  56.     lDate = atol(szDate);
  57.     return lDate;
  58. }

  59. void timev_GetLogTime(char *out_pLogTime)
  60. {
  61.     struct timeb ptm;
  62.     struct tm *ptmb;

  63.     ftime(&ptm);
  64.     ptmb = localtime(&ptm.time);
  65.     sprintf(out_pLogTime, "%02d-%02d %02d:%02d:%02d.%03d", ptmb->tm_mon+1, ptmb->tm_mday,
  66.                        ptmb->tm_hour, ptmb->tm_min, ptmb->tm_sec, ptm.millitm);
  67.     return ;
  68. }

  69. void Log_SysInfo(const int iLogLevel, const char *pszFileName, const int iNum)
  70. {
  71.     int i = 0;
  72.     char szLogTime[30];

  73.     pthread_mutex_lock(&g_WriteLog);

  74.     memset(szLogTime, 0, sizeof(szLogTime));
  75.     memset(g_szLogHead, 0, sizeof(g_szLogHead));

  76.     g_iLogLevel = iLogLevel;

  77.     if(g_iSetLogLevel < g_iLogLevel)
  78.     {
  79.         return;
  80.     }

  81.     Log_Check();

  82.     timev_GetLogTime(szLogTime);
  83.     snprintf(g_szLogHead, sizeof(g_szLogHead), "%s %s L=%d T=%ld E=%d ", szLogTime, pszFileName,
  84.                  iNum, pthread_self(), errno);

  85.     switch(iLogLevel)
  86.     {
  87.         case LOG_LEVEL_ERROR:
  88.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[ERROR] ");
  89.              break;
  90.         case LOG_LEVEL_WARN:
  91.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[WARN] ");
  92.              break;
  93.         case LOG_LEVEL_DEBUG:
  94.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[DEBUG] ");
  95.              break;
  96.         case LOG_LEVEL_INFO:
  97.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[INFO] ");
  98.              break;
  99.         case LOG_LEVEL_ALL:
  100.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[ALL] ");
  101.              break;
  102.         default:
  103.              break;
  104.     }
  105. }

  106. void Log_Check()
  107. {
  108.     struct stat st;
  109.     int iRet;
  110.     char szLogDate[9];

  111.     memset(szLogDate, 0, sizeof(szLogDate));
  112.     memcpy(szLogDate, g_szLogFile + strlen(g_szLogPath) + 1, 8);

  113.     if(atol(szLogDate) == timel_GetCurrentDate())
  114.     {
  115.         if(g_lSetLogSize > 0)
  116.         {
  117.             stat(g_szLogFile, &st);
  118.             if(st.st_size / 1024 / 1024 >= g_lSetLogSize)
  119.             {
  120.                 snprintf(g_szLogFile, sizeof(g_szLogFile), "%s/%ld/%s.%ld%s%06d", g_szLogPath,
  121.                         timel_GetCurrentDate(), g_szLogName,
  122.                         timel_GetCurrentDate(), "_", timel_GetCurrentTime());
  123.             }
  124.             
  125.         }
  126.     }
  127.     else
  128.     {  
  129.         if(g_lSetLogSize > 0)
  130.         {
  131.             snprintf(g_szLogFile, sizeof(g_szLogFile), "%s/%ld/%s.%ld%s%06d", g_szLogPath,
  132.                     timel_GetCurrentDate(), g_szLogName,
  133.                     timel_GetCurrentDate(), "_", timel_GetCurrentTime());

  134.         }
  135.         else
  136.         {
  137.             snprintf(g_szLogFile, sizeof(g_szLogFile), "%s/%ld/%s.%ld", g_szLogPath,
  138.                         timel_GetCurrentDate(), g_szLogName,
  139.                         timel_GetCurrentDate());
  140.         }
  141.     }
  142. }

  143. void Log_Msg(const char *format, ...)
  144. {
  145.     FILE *fp;
  146.     va_list args;
  147.     int  olderrno;
  148.     int i;

  149.     if(g_iSetLogLevel < g_iLogLevel)
  150.     {
  151.         pthread_mutex_unlock(&g_WriteLog);
  152.         return;
  153.     }
  154.     olderrno = errno;     

  155.     if(NULL != (fp = fopen(g_szLogFile, "a+")))
  156.     {
  157.         fprintf(fp, "%s", g_szLogHead);
  158.         va_start(args, format);
  159.         vfprintf(fp, format, args);
  160.         va_end(args);
  161.         fprintf(fp, "%s", "\n");
  162.         fclose(fp);
  163.     }
  164.     else
  165.     {
  166.         printf("fopen error, errno=%d, file=%s\n", errno, g_szLogFile);
  167.         perror("fopen");
  168.     }
  169.     errno = olderrno;

  170.     pthread_mutex_unlock(&g_WriteLog);
  171. }

  172. void *ufs_MallocMemory(const long lSize)
  173. {
  174.     void *pAddr = NULL;
  175.     if(lSize <= 0)
  176.     {
  177.         LOG_ERROR("malloc memory size less than zero");
  178.         return NULL;
  179.     }

  180.     pAddr = malloc(lSize);
  181.     if(NULL == pAddr)
  182.     {
  183.         LOG_ERROR("malloc memory size error!, malloc size(%d)", lSize);
  184.         return NULL;
  185.     }

  186.     memset(pAddr, 0, lSize);

  187.     return pAddr;
  188. }

  189. void ufs_vFreeNormalMemory(void **pAddr)
  190. {
  191.     if(NULL == *pAddr)
  192.         return;
  193.     else
  194.         free(*pAddr);
  195.     *pAddr = NULL;
  196. }

  197. void *trans_SingleThread(void *pData)
  198. {
  199.     int iRet;
  200.     void *pReadMemory = NULL;
  201.     void *pWriteMemory = NULL;

  202.     pWriteMemory = ufs_MallocMemory(20971520);
  203.     if(NULL == pWriteMemory)
  204.     {
  205.         LOG_ERROR("Malloc Memory Failure!");
  206.         ufs_vFreeNormalMemory(&pReadMemory);
  207.         iRet = RT_FAILURE;
  208.         pthread_exit((void *)&iRet);
  209.     }

  210.     pReadMemory = ufs_MallocMemory(20971520);
  211.     if(NULL == pReadMemory)
  212.     {
  213.         LOG_ERROR("Malloc Memory Failure!");
  214.         iRet = RT_FAILURE;
  215.         pthread_exit((void *)&iRet);
  216.     }

  217.     sleep(5);

  218.     LOG_DEBUG("Thread Will Quit [%ld]", pthread_self());

  219.     ufs_vFreeNormalMemory(&pReadMemory);
  220.     ufs_vFreeNormalMemory(&pWriteMemory);


  221.     pthread_exit((void *)&iRet);
  222. }

  223. void *pFunc(void *pData)
  224. {
  225.     int *iTime = (int *)pData;
  226.     long lThreadID[10];
  227.     int i;

  228.     *iTime = 5;
  229.     while(1)
  230.     {
  231.         for(i = 0; i < *iTime; i ++)
  232.         {
  233.             if(pthread_create(&lThreadID[i], NULL, trans_SingleThread, NULL) < 0)
  234.             {
  235.                 printf("create error\n");
  236.                 exit(0);
  237.             }
  238.       

  239.             LOG_DEBUG("Success Create Thread [%ld]", lThreadID[i]);
  240.         }

  241.         for(i = 0; i < *iTime; i ++)
  242.         {
  243.             pthread_join(lThreadID[i], NULL);
  244.             LOG_DEBUG("Thread [%ld] Quit Success!", lThreadID[i]);
  245.         }

  246.         sleep(*iTime * 5);
  247.     }
  248. }

  249. int main(int argc, char *argv[])
  250. {
  251.     long lThreadID[10];
  252.     int i;
  253.     int iRet;
  254.     int iThreadNums;

  255.     iThreadNums = atoi(argv[1]);

  256.     if(iThreadNums > 10 || argc != 2)
  257.     {
  258.         printf("less than 10, or input 2 args!\n");
  259.         exit(0);
  260.     }

  261.     sleep(5);

  262.     for(i = 0; i < iThreadNums; i ++)
  263.     {
  264.         iRet = pthread_create(&lThreadID[i], NULL, pFunc, &iThreadNums);
  265.         if(iRet < 0)
  266.         {
  267.             printf("error ,exit!\n");
  268.             exit(0);
  269.         }

  270.         LOG_DEBUG("Create Initinal Thread [%ld]", lThreadID[i]);
  271.     }

  272.     while(1)
  273.     {
  274.         sleep(2);
  275.     }
  276. }
复制代码
makefile如下
  1. all:TestMemory

  2. TestMemory:thread.o
  3.         cc -o TestMemory thread.o -lpthread
  4.         rm -f thread.o
  5. thread.c:thread.o
  6.         cc -c thread.c
复制代码

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
17 [报告]
发表于 2014-02-13 18:38 |只看该作者
回复 16# korpus


    抓了个strace看了下, LOG_DEBUG存在的时候Glibc没有释放那20M内存给内核。 要想知道详细的原因只能看glibc了, 可惜glibc代码的可读性太差, 不好看啊

论坛徽章:
0
18 [报告]
发表于 2014-02-14 10:02 |只看该作者
回复 17# gaojl0728


    你好,你用strace怎么看的呢?

    如果glibc没有返回给系统,正常吗?

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
19 [报告]
发表于 2014-02-14 10:42 |只看该作者
回复 18# korpus


   
strace -f -p "pid of your program"能看到程序调用的系统调用, 对于大于128K的内存分配, glibc会调用mmap/munmap/madvise分配释放内存,

你的程序分别分配了两块20M的内存,然后分别释放掉:
1. 没有LOG_DEBUG的时候,  一块20M内存是通过munmap释放掉的,另一块20M是madvise释放掉的。
2. 有LOG_DEBUG的时候, 一块20M内存是通过munmap释放掉的, 另一块没有释放被glibc 回收缓存了。

通常内存池会回收并缓存释放的内存而不归还给内核,这是正常的行为,不是内存泄露。
要想知道原因只能看glibc的源代码, 可能pthread的相关函数做了某些特殊处理。

论坛徽章:
0
20 [报告]
发表于 2014-02-14 11:35 |只看该作者
回复 19# gaojl0728


    谢谢你哈。我看看。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP