免费注册 查看新帖 |

Chinaunix

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

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

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

架构是这样的。

主进程先初始化了一个线程池A,当其中一个线程接收到任务的时候,就会去创建几个子线程B来处理任务。(该A1线程使用pthread_jion等待子线程B退出,子线程用pthread_exit退出)。在子线程B中,使用了malloc函数连续分配了2段内存。任务处理完后,在退出pthread_exit前,释放他们。

其中的异常现象是这样的,如果我在子线程B中加了日志打印的函数,那么所有子线程退出时,上面申请的两个连续内存有一半的大小在top中显示为未释放(实际上,已经释放了,我向那2段内存中memcpy程序core了)。如果我在子线程B中不加日志打印函数,就不会有这个现象。

日志打印函数,检查过,没有什么问题。

  1. #define LOG_INFO        Log_SysInfo(LOG_LEVEL_INFO,__FILE__,__LINE__),Log_Msg

  2. void Log_SysInfo(const int iLogLevel, const char *pszFileName, const int iNum)
  3. {
  4.     int i = 0;
  5.     char szLogTime[30];

  6.     //  加一个写日志的线程锁
  7.     pthread_mutex_lock(&g_WriteLog);

  8.     memset(szLogTime, 0, sizeof(szLogTime));
  9.     memset(g_szLogHead, 0, sizeof(g_szLogHead));

  10.     g_iLogLevel = iLogLevel;

  11.     //  如果设置的日志级别小直接返回
  12.     if(g_iSetLogLevel < g_iLogLevel)
  13.     {
  14.         return;
  15.     }

  16.     Log_Check();

  17.     timev_GetLogTime(szLogTime);
  18.     snprintf(g_szLogHead, sizeof(g_szLogHead), "%s %s L=%d T=%ld E=%d ", szLogTime, pszFileName,
  19.                  iNum, pthread_self(), errno);

  20.     switch(iLogLevel)
  21.     {
  22.         case LOG_LEVEL_ERROR:
  23.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[ERROR] ");
  24.              break;
  25.         case LOG_LEVEL_WARN:
  26.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[WARN] ");
  27.              break;
  28.         case LOG_LEVEL_DEBUG:
  29.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[DEBUG] ");
  30.              break;
  31.         case LOG_LEVEL_INFO:
  32.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[INFO] ");
  33.              break;
  34.         case LOG_LEVEL_ALL:
  35.              sprintf(g_szLogHead + strlen(g_szLogHead), "%s", "[ALL] ");
  36.              break;
  37.         default:
  38.              break;
  39.     }
  40. }

  41. void Log_Msg(const char *format, ...)
  42. {
  43.     FILE *fp;
  44.     va_list args;
  45.     int  olderrno;
  46.     //char szContext[1024*10];    //  分配10K的临时变量空间,如果用内存分配会不会影响性能
  47.     int i;

  48.     //  如果设置的日志级别小,则直接返回
  49.     if(g_iSetLogLevel < g_iLogLevel)
  50.     {
  51.         pthread_mutex_unlock(&g_WriteLog);
  52.         return;
  53.     }
  54.     olderrno = errno;     
  55.     //memset(szContext, 0, sizeof(szContext));

  56.     if(NULL != (fp = fopen(g_szLogFile, "a+")))
  57.     {
  58.         fprintf(fp, "%s", g_szLogHead);
  59.         va_start(args, format);
  60. //        fprintf(fp, "%s\n", szContext);
  61.         vfprintf(fp, format, args);
  62. //        fflush(fp);
  63.         va_end(args);
  64.         fprintf(fp, "%s", "\n");
  65.         fclose(fp);
  66.     }
  67.     else
  68.     {
  69.         printf("fopen error, errno=%d, file=%s\n", errno, g_szLogFile);
  70.         perror("fopen");
  71.         //printf("context1 [%s], file[%s:%d] \n", szContext, __FILE__, __LINE__);
  72.     }
  73.     errno = olderrno;

  74.     pthread_mutex_unlock(&g_WriteLog);
  75. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2014-02-12 14:45 |只看该作者
这个是子线程的代码,就算是这样,先连续申请两段内存,然后释放,top中显示就没有释放完。  如果我在pReadMemory申请后,再释放,pWriteMemory申请后,再释放就是正常的。搞不懂是什么意思,求大哥大姐帮帮忙!
  1. void *trans_SingleThread(void *pData)
  2. {
  3.     int iRet;
  4.     MultTransData *pMultTransData = (MultTransData *)pData;
  5.     MMapData *pMMapData = NULL;
  6.     ListNode *pTemp = NULL;
  7.     void *pReadMemory = NULL;
  8.     void *pWriteMemory = NULL;
  9.     MMapData *pFirstSection = NULL;

  10.     pTemp = pMultTransData->m_pMMapDataList;
  11.     pFirstSection = (MMapData *)pTemp->pData;


  12.     //  为写空间分配内存地址
  13.     pWriteMemory = ufs_MallocMemory(pFirstSection->m_lWriteTotalSize);
  14.     if(NULL == pWriteMemory)
  15.     {
  16.         LOG_ERROR("Malloc Memory Failure!");
  17.         ufs_vFreeNormalMemory(&pReadMemory);
  18.         iRet = RT_FAILURE;
  19.         pthread_exit((void *)&iRet);
  20.     }

  21.     //  为读空间分配内存地址
  22.     pReadMemory = ufs_MallocMemory(pFirstSection->m_lReadTotalSize);
  23.     if(NULL == pReadMemory)
  24.     {
  25.         LOG_ERROR("Malloc Memory Failure!");
  26.         iRet = RT_FAILURE;
  27.         pthread_exit((void *)&iRet);
  28.     }


  29. LOG_DEBUG("Thread Will Quit");

  30. ufs_vFreeNormalMemory(&pReadMemory);
  31. ufs_vFreeNormalMemory(&pWriteMemory);



  32. pthread_exit((void *)&iRet);

  33. }
复制代码

论坛徽章:
0
3 [报告]
发表于 2014-02-12 16:11 |只看该作者
求帮助!有没有哪个可以帮忙看看呢

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
4 [报告]
发表于 2014-02-12 16:43 |只看该作者
本帖最后由 gaojl0728 于 2014-02-12 16:45 编辑

回复 3# korpus


    1. 能不能把LOG_DEBUG的代码贴出来。
2. 你是看top的哪一个字段?
3. 你说“我向那2段内存中memcpy程序core了”, 什么叫core了, 是crash了吗?
4. crash了, 不一定能证明就是释放了, 把memcpy的代码贴出来

论坛徽章:
0
5 [报告]
发表于 2014-02-12 16:56 |只看该作者
回复 4# gaojl0728


    你好,谢谢你的关注,
1 LOG_DEBUG,贴出来了 ,就在第一个代码里面的
2 top的res字段
3 意思好像没有表达清楚,意思是,在我free那2段内存后,为了检查是否真的释放了,然后向释放的内存memcpy内容,然后程序crash了
4 memcpy(pReadMemory, "12345", 5);

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
6 [报告]
发表于 2014-02-12 17:10 |只看该作者
1. 你第一行贴的是LOG_INFO, 我想看看LOG_DEBUG。
2. ufs_vFreeNormalMemory传递的为什么是双重指针,难道会把参数设置为NULL?
如果是写NULL的话,你就不需要memcpy测试了, 直接看看是不是NULL就行了
3. 能不能把ufs_MallocMemory和ufs_vFreeNormalMemory的代码贴出来看看?
如果实现是用的malloc和free, 那内存可能被glibc的内存池回收了,并没有还给内核。把代码贴出来看看吧
4. pFirstSection->m_lWriteTotalSize和pFirstSection->m_lReadTotalSize的大小多少?

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


    1. 你第一行贴的是LOG_INFO, 我想看看LOG_DEBUG。
2. ufs_vFreeNormalMemory传递的为什么是双重指针,难道会把参数设置为NULL?
如果是写NULL的话,你就不需要memcpy测试了, 直接看看是不是NULL就行了
3. 能不能把ufs_MallocMemory和ufs_vFreeNormalMemory的代码贴出来看看?
如果实现是用的malloc和free, 那内存可能被glibc的内存池回收了,并没有还给内核。把代码贴出来看看吧
4. pFirstSection->m_lWriteTotalSize和pFirstSection->m_lReadTotalSize的大小多少?

论坛徽章:
0
8 [报告]
发表于 2014-02-12 17:37 |只看该作者
回复 7# gaojl0728


    你好,首先谢谢您哈。
1. 你第一行贴的是LOG_INFO, 我想看看LOG_DEBUG。
  1. #define LOG_ERROR        Log_SysInfo(LOG_LEVEL_ERROR,__FILE__,__LINE__),Log_Msg
  2. #define LOG_WARN        Log_SysInfo(LOG_LEVEL_WARN,__FILE__,__LINE__),Log_Msg
  3. #define LOG_INFO        Log_SysInfo(LOG_LEVEL_INFO,__FILE__,__LINE__),Log_Msg
  4. #define LOG_DEBUG        Log_SysInfo(LOG_LEVEL_DEBUG,__FILE__,__LINE__),Log_Msg
复制代码
2. ufs_vFreeNormalMemory传递的为什么是双重指针,难道会把参数设置为NULL?
如果是写NULL的话,你就不需要memcpy测试了, 直接看看是不是NULL就行了


是的,就是为了将其置为空,打印过,释放后,确实也是NULL

3.函数如下
  1. void *ufs_MallocMemory(const long lSize)
  2. {
  3.     void *pAddr = NULL;
  4.     if(lSize <= 0)
  5.     {
  6.         LOG_ERROR("malloc memory size less than zero");
  7.         return NULL;
  8.     }

  9.     pAddr = malloc(lSize);
  10.     if(NULL == pAddr)
  11.     {
  12.         LOG_ERROR("malloc memory size error!, malloc size(%d)", lSize);
  13.         return NULL;
  14.     }

  15.     memset(pAddr, 0, lSize);

  16.     return pAddr;
  17. }

  18. void ufs_vFreeNormalMemory(void **pAddr)
  19. {
  20. //    LOG_WARN("TEST MEMORY FREE[%p]", *pAddr);

  21.     if(NULL == *pAddr)
  22.         return;
  23.     else
  24.         free(*pAddr);
  25.     *pAddr = NULL;
  26. }
复制代码
是用的malloc与free,在网上也查了说有可能被glibc回收,但是每次我运行一次的时候,内存就增加了。

4. pFirstSection->m_lWriteTotalSize和pFirstSection->m_lReadTotalSize的大小多少?
这几个值是设定的值,一般在10M以上

再次谢谢哈

论坛徽章:
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
9 [报告]
发表于 2014-02-12 17:59 |只看该作者
内存的问题我不猜~~



>>但是每次我运行一次的时候,内存就增加了。

如果是指进程已经结束重跑的话。
就不用担心内存问题了。
进程一结束,
渗漏的内存也会被OS自动回收。

论坛徽章:
3
射手座
日期:2014-08-18 12:15:53戌狗
日期:2014-08-22 09:53:36寅虎
日期:2014-08-22 14:15:29
10 [报告]
发表于 2014-02-12 18:17 |只看该作者
本帖最后由 gaojl0728 于 2014-02-12 18:22 编辑

回复 8# korpus

glibc只是一个可疑的点,但是不确定是不是真的被内存池回收而没换给内核了。
看你的代码没什么问题, 没有内存泄露, 也没看到死锁
如果不是被内存池缓存的话,我感觉可能只是一个top的显示问题
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP