pthread_create会导致内存泄露

这几天一直在调试一个系统,系统的功能就是定时发送数据、接收数据然后解析收到的数据,转换成一定的格式存入数据库中。我为了并发操作,所以每接收到一个数据包,就调用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)

问题解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383395.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux_linux常用工具之make/makefile详解

make/makefile make/makefile: 项目自动化构建工具 makefile:普通文本文件&#xff0c;记录了项目的构建流程规则。 make: 一个解释程序&#xff0c;到当前执行make命令的目录下寻找makefile文件&#xff0c;并且对makefile 中记录的项目构建规则进行解释执行。makefile: 编写…

Linux_linux常用工具(git,vim ,gcc ,gdb,权限)超详解

git :项目版本控制工具 项目克隆&#xff1a;git clone项目提交&#xff1a;git add&#xff08;本地仓库提交&#xff09; git commit -m “bak msg”&#xff08;-m 备注信息&#xff09;同步到服务器&#xff1a;git push origin master&#xff08;提交到主分支&…

T20调试札记

最近在调试T20的内存&#xff0c;使用的指令在此记录一下 1. pmap指令查看指定进程中的内存分布。该指令需要在busybox中开启 pmap -x 111 2.应用与so需要执行strip操作&#xff0c;可以减小存储空间的大小 mips-linux-gnu-strip libsysutils.so 3.nm指令和file指令可以查…

samba 2.2.7a 编译

今天在君正T20上编译samba 2.2.7a 遇到了一些问题&#xff0c;特此记录一下 1.自己写一个build.sh脚本&#xff0c;方便后续的再次编译 #!/bin/sh # export CFLAGS"-O2 -muclibc" export CPPFLAGS"-O2 -muclibc" export CXXFLAGS"-O2 -muclibc&qu…

Linux_linux常用工具------进度条程序

缓冲区对文件读写的影响&#xff1a;数据并没有直接写入文件&#xff0c;而是写入到缓冲区&#xff08;内存&#xff09;中&#xff0c;等到缓冲区中数据写满或者刷新缓冲区的时候&#xff0c;才会将数据真正的写入文件 fflush&#xff08;stdout&#xff09;刷新。 回车与换行…

Ubuntu下QT的安装详细教程

本文转自&#xff1a;http://blog.chinaunix.net/uid-7945126-id-4987195.html 经测试完美解决 ------------------------------------------------------------- 最近需要在Ubuntu下开发桌面软件&#xff0c;想起了QT。书上介绍的方法太老了&#xff0c;网上找了一大堆安装方法…

Linux_linux常用工具---闲杂篇(除了vim, 还有哪些常用的牛逼的编辑器, 并能够横向对比编辑器之间的区别和优缺点.)

vim自行查找资料, 自行配置插件. 借鉴别人的 " 显示相关 “”""""""""""""""""""""""""""""""""&…

ubuntu14.04下安装qt4.8.6 +qt creator

原创作品&#xff0c;允许转载&#xff0c;转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://248341.blog.51cto.com/238341/1438867以前安装时没太注意&#xff0c;安装qt后发现在qt creator下无法输入中文&#xff0c;或者中文无法…

网络基础一(协议的概念,网络应用程序设计模式)

协议的概念 什么是协议&#xff1f; 从应用的角度出发&#xff0c;协议可理解为“规则”&#xff0c;是数据传输和数据的解释的规则。 假设&#xff0c;A、B双方欲传输文件。规定&#xff1a; 第一次&#xff0c;传输文件名&#xff0c;接收方接收到文件名&#xff0c;应答OK…

ubuntu修改root密码

sudo passwd root [sudo] password for you &#xff1a;---> 输入你的密码&#xff0c;不会显示 Enter new UNIX password: --- > 设置root 密码 Retype new UNIX password: --> 重复

linux 消息队列机制

现在我们来讨论第三种也是最后一种System V IPV工具&#xff1a;消息队列。在许多方面看来&#xff0c;消息队列类似于有名管道&#xff0c;但是却没有与打开与关闭管道的复杂关联。然而&#xff0c;使用消息队列并没有解决我们使用有名管道所遇到的问题&#xff0c;例如管道上…

堆(概念,数据结构中堆与内存堆区的区别 ,堆的基本操作)

堆的特性&#xff1a; 必须是完全二叉树 用数组实现 任一结点的值是其子树所有结点的最大值或最小值 最大值时&#xff0c;称为“最大堆”&#xff0c;也称大根堆&#xff1b; 在完全二叉树中&#xff0c;任何一个子树的最大值都在这个子树的根结点。最小值时&#xff0c;称为…

makefile中的shell调用---注意事项

在之前一次编写makfile时候&#xff0c;有看到相关的makefile中使用$$来引用变量&#xff0c;而且尝试后发现$$使用居然和${}有类似的功能。当时也没具体追究相关的用法&#xff0c;当然刚才所说的都是错误的观念 $$&#xff1a;在makefile中会被替换成一个$。 相关资料是这么描…

网络基础2(分层模型,通信过程,以太网,ARP协议格式和具体功能详解)

分层模型 OSI七层模型 OSI模型 1 物理层&#xff1a;主要定义物理设备标准&#xff0c;如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流&#xff08;就是由1、0转化为电流强弱来进行传输&#xff0c;到达目的地后再转化为1、0&#…

为github帐号添加SSH keys

使用git clone命令从github上同步github上的代码库时&#xff0c;如果使用SSH链接&#xff08;如我自己的beagleOS项目&#xff1a;gitgithub.com:DamonDeng/beagleOS.git&#xff09;&#xff0c;而你的SSH key没有添加到github帐号设置中&#xff0c;系统会报下面的错误&…

网络基础3(IP段格式,UDP数据报格式,TCP数据报格式)

IP段格式 IP数据报的首部长度和数据长度都是可变长的&#xff0c;但总是4字节的整数倍。 对于IPv4&#xff0c;4位版本字段是4。4位首部长度的数值是以4字节为单位的&#xff0c;最小值为5&#xff0c;也就是说首部长度最小是4x520字节&#xff0c;也就是不带任何选项的IP首部…

Linux 开发路线

Linux 开发路线&#xff1a; 使用 linux—〉linxu 系统编程开发---〉驱动开发和分析 linux 内核 开始学 linux 内核:最好有三件宝物:《深入理解 linux 内核》《LINUX内核源代码情景分析》和源代码。 《深》是纲,《情》是目。最后深入代码 Linux 内核原理&#xff1a;比较浅显…

堆的应用(堆排序,TopK问题)

堆的应用 1&#xff09;排序 堆排序 选择排序 既可以找到最大的放在最后 也可以找到最小的方最前 但是&#xff0c;堆排序不能找最小的放在最前 因为把最小数放在最前&#xff0c;会破坏掉堆的原来的顺序&#xff0c;除非重新建堆 1&#xff0c; 2&#xff0c;9&#xff0c…

有名管道和无名管道的区别

1&#xff09;无名管道:管道是半双工的&#xff0c;数据只能向一个方向流动&#xff1b;需要双方通信时&#xff0c;需要建立起两个管道&#xff1b;只能用于父子进程或者兄弟进程之间&#xff08;具有亲缘关系的进程&#xff09;。 单独构成一种独立的文件系统&#xff1a;管道…

网络基础4(TCP三次握手,四次握手,TCP流量控制,TCP状态转换 , TCP异常断开,设置TCP属性,端口复用)

TCP协议 TCP通信时序 下图是一次TCP通讯的时序图。TCP连接建立断开。包含大家熟知的三次握手和四次握手。 TCP通讯时序 在这个例子中&#xff0c;首先客户端主动发起连接、发送请求&#xff0c;然后服务器端响应请求&#xff0c;然后客户端主动关闭连接。 两条竖线表示通讯的…