这几天一直在调试一个系统,系统的功能就是定时发送数据、接收数据然后解析收到的数据,转换成一定的格式存入数据库中。我为了并发操作,所以每接收到一个数据包,就调用pthread_create函数创建一个默认属性的线程进行处理。

系统一开始运行很正常,但是当接收到第299个数据包时,就发生异常,查看程序日志,得知原来自接收到299个数据包后,就不再解析接收到的数据。我本以为是网络的问题,于是,重启下程序,结果异常发生在了同样的位置。这时,我猜想可能是代码的问题,找到相关代码,如下:

while (1) 
{
    len = recvfrom(sock, buf, MAXPACKETSIZE, 

                    0,(struct sockaddr *)&c_addr, &addr_len);
    .......
    targ = (struct threadarg *)malloc(sizeof(struct threadarg));
    memset(targ, 0, sizeof(struct threadarg));
        
    targ->len = len;
    targ->ip = (int)c_addr.sin_addr.s_addr;
    memcpy(targ->buffer, buf, len);
    printf("received\n");
        

    //注:targ在线程中会被free掉。

    pthread_create(&tid, NULL, insertToList, (void *)targ);
}

从代码看不出什么异常,由于解析数据是调用pthread_create函数创建一个默认属性的线程进行处理,如果没有解析,那么,应该是pthread_create函数没有创建成功。而pthread_create函数创建失败最可能的原因应该就是系统资源不足,根据经验,线程的默认堆栈大小是1MB,就是说,系统每创建一个线程就要至少提供1MB的内存,那么,创建线程失败,极有可能就是内存不够用了。从代码中看不出有内存泄露的现象,有malloc的地方就会有free对应。而仍然出现问题,那么,唯一的解释就是pthread_create会导致内存泄露! pthread_create创建的线程结束后,系统并未回收其资源,从而导致了泄露。

然后从网上查了相关资料如下:


     线程的分离状态决定一个线程以什么样的方式来终止自己。线程的默认属性是非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。


     从上面的描述中可以得知如果调用pthread_create函数创建一个默认非分离状态的线程,如果不用pthread_join()函数,线程结束时并不算终止,所以仍然会占用系统资源。这里有如下几种方法解决这个问题:
1.使用pthread_join()函数回收相关内存区域。

pthread_t tid;
void* state;

pthread_create(&tid, NULL, test, NULL);
pthread_join(tid, &state);

2.可以调用 pthread_detach() 函数分离线程。

pthread_t tid;
pthread_create(&tid, NULL, test, NULL);
pthread_detach(tid);

当然,也可以在 thread function 中调用。

void* test(void* arg)
{
    .....
    pthread_detach(pthread_self());
    return NULL;
}


3.使用线程属性。

pthread_attr_t attr;
pthread_t tid;

pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

pthread_create(&tid, &attr, test, NULL);

sleep(3);//等待线程结束

pthread_attr_destroy(&attr);

根据实际需要,任选其一即可。

ps:最后,我写了个测试程序,然后用valgrind检查了一下。
测试程序:

#include <pthread.h>
#include <stdio.h>

void* test()
{
    printf("ok\n");
    return;
}
int main(int argc, char** argv)
{
        pthread_t tid;
        pthread_create(&tid, NULL, test, NULL);
    //pthread_join(tid, NULL);

return 1;
}

编译链接:
[root@localhost ~]# gcc -g b.c -o b -lpthread
然后,用valgrind进行内存检查


[root@localhost ~]# valgrind --tool=memcheck --leak-check=full ./b
==20980== Memcheck, a memory error detector
==20980== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20980== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20980== Command: ./b
==20980== 
ok
==20980== 
==20980== HEAP SUMMARY:
==20980==     in use at exit: 272 bytes in 1 blocks
==20980==   total heap usage: 1 allocs, 0 frees, 272 bytes allocated
==20980== 
==20980== 272 bytes in 1 blocks are possibly lost in loss record 1 of 1
==20980==    at 0x4C1F1A0: calloc (vg_replace_malloc.c:418)
==20980==    by 0x4010422: _dl_allocate_tls (in /lib64/ld-2.7.so)
==20980==     by 0x4E2AB52: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.7.so)
==20980==    by 0x40059E: main (b.c:13)
==20980== 
==20980== LEAK SUMMARY:
==20980==    definitely lost: 0 bytes in 0 blocks
==20980==    indirectly lost: 0 bytes in 0 blocks
==20980==       possibly lost: 272 bytes in 1 blocks
==20980==    still reachable: 0 bytes in 0 blocks
==20980==         suppressed: 0 bytes in 0 blocks
==20980== 
==20980== For counts of detected and suppressed errors, rerun with: -v
==20980== ERROR SUMMARY:  1 errors from 1 contexts  (suppressed: 4 from 4)


确实有内存泄露。
修改测试程序:

#include <pthread.h>
#include <stdio.h>

void* test()
{
    printf("ok\n");
    return;
}
int main(int argc, char** argv)
{
        pthread_t tid;
        pthread_create(&tid, NULL, test, NULL);
    pthread_join(tid, NULL);
    return 1;
}

编译链接:
[root@localhost ~]# gcc -g b.c -o b -lpthread
然后,用valgrind进行内存检查


[root@localhost ~]# valgrind --tool=memcheck --leak-check=full ./b
==21013== Memcheck, a memory error detector
==21013== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==21013== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==21013== Command: ./b
==21013== 
ok
==21013== 
==21013== HEAP SUMMARY:
==21013==     in use at exit: 0 bytes in 0 blocks
==21013==    total heap usage: 1 allocs, 1 frees, 272 bytes allocated
==21013== 
==21013== All heap blocks were freed -- no leaks are possible
==21013== 
==21013== For counts of detected and suppressed errors, rerun with: -v
==21013== ERROR SUMMARY:  0 errors from 0 contexts  (suppressed: 4 from 4)


问题解决。

pthread_create会导致内存泄露相关推荐

  1. NSTimer 增加引用计数, 导致内存泄露,

    NSTimer 增加引用计数, 导致内存泄露, self.adTimer   = [NSTimerscheduledTimerWithTimeInterval:5.0target:selfselect ...

  2. 使用ThreadLocal不当可能会导致内存泄露

    使用ThreadLocal不当可能会导致内存泄露 基础篇已经讲解了ThreadLocal的原理,本节着重来讲解下使用ThreadLocal会导致内存泄露的原因,并讲解使用ThreadLocal导致内存 ...

  3. VC 2010的MFC函数,CMFCVisualManager::GetInstance()可能导致内存泄露

    今天在网上看到一篇文章,关于CMFCVisualManager的内存泄露问题( 链接是 http://zhanyonhu.blog.163.com/blog/static/16186044201132 ...

  4. String 使用不当可能导致内存泄露

    转载自   String 使用不当可能导致内存泄露 String是Java中一个比较基础的类,每一个开发人员都会经常接触到.而且,String也是面试中经常会考的知识点.String有很多方法,有些方 ...

  5. inputstreamreader未关闭会导致oom_ThreadLocal 一定会导致内存泄露?

    在面试的时候,ThreadLocal作为高并发常用工具经常会被问到.而面试官比较喜欢问的问题有以下两个: 1.ThreadLocal是怎么实现来保证每个线程的变量副本的. 2.ThreadLocal的 ...

  6. android弹出输入法内存,android 输入法导致内存泄露问题

    该方法侵入太高,必须重新EditText,如果我们直接使用一个第三方的控件包含了EditText,那么这么做就没有意义,所以放弃了这种方案,然后我又想出了其他方案,Android 输入法导致内存泄露以 ...

  7. terminatethread导致内存泄露

    terminatethread导致内存泄露,waitforsingleobject又容易导致UI卡死,真头疼 听过无数次不要TerminateThread,只是工作中常用,貌似也没有什么问题.今天在高 ...

  8. 什么情况下会导致内存泄露

    Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的可能是24M,当我们的内存占用超过了一定的程度后,就会出现OutOfMemory的错误. 下面说明几点可能导致内存泄露 ...

  9. 什么是内存溢出与内存泄露,几种常见导致内存泄露的写法

    最近朋友推荐了一篇关于内存溢出与内存泄漏的文章,感觉写的还不错,于是便在网上搜索了一番,对这块进行了加固,发现自己之前写的代码也存在一些内存泄漏的风险,所以弄懂内存泄漏与内存溢出是很有利于我们提高代码 ...

最新文章

  1. 如何成为一个好的测试工程师(转载,大意)
  2. 网站更新的文章如何被百度快速收录?
  3. python读取txt数据-Python读取txt数据文件,并作图
  4. 静态方法与单例模式的区别以及为什么要用单例模式而不是静态方法
  5. Jenkins 随笔
  6. Python学习day2 while循环格式化输出运算符
  7. 用Python解决百马百瓦
  8. lr11 打开controller时,会提示提示cannot initialize driver dll,exiting
  9. 套料排版代码python_XSuperNEST全自动套料解决方案
  10. 百度SEO站群PTCMS全自动采集小说网站源码
  11. ITIL服务管理知识体系的介绍
  12. CSS3实现渐变背景
  13. NAT技术与代理服务器详解
  14. 科目三远光灯怎么开图解?科三远光灯是往上还是往下
  15. 论文笔记 ACL 2021|Capturing Event Argument Interaction via A Bi-Directional Entity-Level Recurrent Decod
  16. winform 分页打印实例
  17. 性别计算机英语怎么说,性别教育用英语怎么说?
  18. nodejs 安装及环境配置
  19. 微软Win11应用商店功能增强:允许用户备份/修复游戏
  20. Hook技术在APP测试中的应用

热门文章

  1. jenkins-基础配置
  2. 2018.2.28(延迟加载和缓存)
  3. 初始Windows程序
  4. 即时聊天IM之二 openfire 整合现有系统用户
  5. apache2.4.x三种MPM介绍
  6. 使用BizTalk Server常见问题处理
  7. java动态拼接请求_在JavaWeb项目中处理静态文件或动态链接拼接网站地址的最优处理方案...
  8. python爬虫requests实战_Python爬虫之requests库网络爬取简单实战
  9. linux php7 mongodb,CentOS 7下安装配置PHP7跟LAMP及MongoDB和Redis
  10. linux live cd ubuntu,在Windows 7上体验Ubuntu Live CD