• 多线程编程中使用pthread_create内存泄露问题


    //tls5源代码:

    #include <stdio.h>

    #include <unistd.h>

    #include <string.h>

    #include "pthread.h"

    #include "TLS/Tlsconf.h"

    #include "TLS/tls_api.h"

    #define ERROR  -1

    #define OK     0

    void test_fn2(int a)

    {

      char  *psz = (char*)get_buf(ENUM_1, 32);

      printf("thread(%u) psz: %s ", pthread_self(), psz);

      memset(psz, 0, 32);

      sprintf(psz, "%u_%d", pthread_self(), a);

      return;

    }

    void test_fn1(int a)

    {

      int  *reti = (int*)get_buf(ENUM_0, sizeof(int));

      printf("thread(%u) reti: %d ", pthread_self(), *reti);

      (*reti)++;

      test_fn2(a);

      return;

    }

    void* test_fn_main1(void* arg)

    {

      int i = 0;

      for (i = 0; i < 3; i++)

      {

          test_fn1(i);

          sleep(1);

      }

      return;

    }

    int main()

    {

      int iRet = ERROR;

      int i = 0;

      pthread_t   tid;

      printf("test start! ");

      for (i = 0; i < 5; i++)

      {

          iRet = pthread_create(&tid, NULL, test_fn_main1, NULL);

          if (OK != iRet)

          {

              printf("pthread_create error! ");

              return ERROR;

          }

          //pthread_detach(tid);

      }

      sleep(10);

      return OK;

    }

    //生成可执行程序:tls库见上一篇

    gcc -o tls5 tlstest5.c TLS/libtls.a -lpthread -lstdc++

    //用valgrind进行内存泄露监测:

    valgrind -v --leak-check=full --tool=memcheck ./tls5

    提示信息:

    [root@localhost 20130713]# valgrind -v --leak-check=full --tool=memcheck ./tls5

    …………

    ==31803== malloc/free: in use at exit: 720 bytes in 5 blocks.

    ==31803== malloc/free: 40 allocs, 35 frees, 1,220 bytes allocated.

    ==31803==

    ==31803== searching for pointers to 5 not-freed blocks.

    ==31803== checked 52,519,768 bytes.

    ==31803==

    ==31803==

    ==31803== 720 bytes in 5 blocks are possibly lost in loss record 1 of 1

    ==31803==    at 0x4004824: calloc (vg_replace_malloc.c:279)

    ==31803==    by 0x840B39: _dl_allocate_tls (in /lib/ld-2.6.so)

    ==31803==    by 0x9F1B35: pthread_create@@GLIBC_2.1 (in /lib/libpthread-2.6.so)

    ==31803==    by 0x8048ACA: main (in /mnt/hgfs/D/work/test/20130713/tls5)

    ==31803==

    ==31803== LEAK SUMMARY:

    ==31803==    definitely lost: 0 bytes in 0 blocks.

    ==31803==      possibly lost: 720 bytes in 5 blocks.

    ==31803==    still reachable: 0 bytes in 0 blocks.

    ==31803==         suppressed: 0 bytes in 0 blocks.

    …………

    IN SUMMARY: 16 errors from 8 contexts (suppressed: 0 from 0)主要是库里面使用了未初始化的变量(Conditional jump or move depends on uninitialised value(s)),不管它。主要问题是在malloc/free: 40 allocs, 35 frees, 1,220 bytes allocated。

    查看代码及程序运行打印,malloc与free都是一一对应的,怎会出现未释放的内存块?另外,程序共创建了5个线程,每个线程中有两次malloc操作,应该10 allocs,怎会是40allocs?排查步骤如下:

    步骤一:

    void* test_fn_main1(void* arg)

    {

      int i = 0;

      for (i = 0; i < 3; i++)

      {

          //test_fn1(i);         //注释掉该行不再调用malloc

          sleep(1);

      }

      return;

    }

    步骤二:

    [root@localhost 20130713]# gcc -o tls5 tlstest5.c TLS/libtls.a -lpthread -lstdc++

    [root@localhost 20130713]# valgrind -v --leak-check=full --tool=memcheck ./tls5

    ………………

    ==2237== malloc/free: in use at exit: 720 bytes in 5 blocks.

    ==2237== malloc/free: 5 allocs, 0 frees, 720 bytes allocated.

    ==2237==

    ==2237== searching for pointers to 5 not-freed blocks.

    ==2237== checked 52,526,684 bytes.

    ==2237==

    ==2237==

    ==2237== 720 bytes in 5 blocks are possibly lost in loss record 1 of 1

    ==2237==    at 0x4004824: calloc (vg_replace_malloc.c:279)

    ==2237==    by 0x840B39: _dl_allocate_tls (in /lib/ld-2.6.so)

    ==2237==    by 0x9F1B35: pthread_create@@GLIBC_2.1 (in /lib/libpthread-2.6.so)

    ==2237==    by 0x8048ABF: main (in /mnt/hgfs/D/work/test/20130713/tls5)

    ==2237==

    ==2237== LEAK SUMMARY:

    ==2237==    definitely lost: 0 bytes in 0 blocks.

    ==2237==      possibly lost: 720 bytes in 5 blocks.

    ==2237==    still reachable: 0 bytes in 0 blocks.

    ==2237==         suppressed: 0 bytes in 0 blocks.

    --2237--  memcheck: sanity checks: 2 cheap, 1 expensive

    …………

    我们发现,程序中即使没有调用malloc,也存在5 allocs,纵观测试代码,唯一有可能alloc的地方就只有pthread_create了。

    上网查了一下,在http://blog.csdn.net/jiqiren007/article/details/5959810找到答案。

    线程在创建时都会分配一些内存(valgrind里面alloc次数是怎么算的,不是很清楚!),这些内存默认情况下需要在主线程中调用pthread_join进行释放;或者可以将子线程从父线程剥离,子线程终止时会回收这些内存资源。如果不使用pthread_join或者pthread_detach,线程结束时,pthread_create产生的内存将一直存在,直到整个进程结束为止,造成内存泄露。

    在pthread_create后面加上pthread_detach(tid),结果如下:

    …………………………

    ==3206== malloc/free: in use at exit: 0 bytes in 0 blocks.

    ==3206== malloc/free: 40 allocs, 40 frees, 1,220 bytes allocated.

    ==3206==

    ==3206== All heap blocks were freed -- no leaks are possible.

    --3206--  memcheck: sanity checks: 2 cheap, 1 expensive

    --3206--  memcheck: auxmaps: 0 auxmap entries (0k, 0M) in use

    --3206--  memcheck: auxmaps: 0 searches, 0 comparisons

    ……………………

    问题解决!

    从这个问题可以看出,如果大量地启动子线程,却不对子线程进行任何处理(调用pthread_join或者pthread_detach),最终有可能导致内存大量地隐秘地被蚕食。这个过程缓慢而又难以发掘,不过带来的问题却是极严重的。

  • 相关阅读:
    转换方法
    数组去重
    js常见兼容
    封装cookie
    常用函数封装
    手绘 代码
    Python变量和数据类型,类型转换
    语句块的概念及注释符的使用
    ipython和pip,模块安装方法
    第一个python程序
  • 原文地址:https://www.cnblogs.com/wxyy/p/3191862.html
Copyright © 2020-2023  润新知