2.1 线程栈泄漏(Joinable线程栈)一个导致线程栈泄漏原因可能是对于一个Joinable线程 , 系统会创建线程私有的栈、threand ID、线程结束状态等信息 。
如果此线程没有pthread_join() , 那么系统不会对以上信息进行回收 。这就可能造成线程栈等泄漏 。
确定线程栈泄漏的方法是:通过ls /proc/<pid>/task | wc -l确定进程下线程数目 。然后在maps中检查[stack:TID]数目 。两者如果不一致 , 则存在Joinable线程没有调用pthread_join()造成的泄漏 。
如果maps没有[stack:TID] , 可以通过pmap <pid> | grep <stack size> | wc -l , 即通过检查栈大小的vma数目来确定栈数目 。
3. 问题根源通过检查线程栈消耗与实际线程数目 , 发现两者数目吻合 。所以线程并没有退出 。也即不是由于未使用pthread_join()导致的内存泄漏 。
然后根据maps中[stack:TID]的pid号 , cat /proc/<pid>/comm发现是同一个线程不停创建 。但是没有释放 。
其实通过top -H -p <pid>和maps也可发现问题 , 中间走了弯路 。
所以问题的根源是 , 进程不停创建但是没有退出造成内存消耗殆尽 。
相关视频推荐
内存泄漏的3个解决方案与原理实现 , 知道一个可以轻松应对开发
4种实时线上内存泄漏检测的实现方式【linux后台开发】
学习地址:C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂
需要C/C++ linux服务器架构师学习资料加qun812855908获取(资料包括C/C++ , Linux , golang技术 , Nginx , ZeroMQ , MySQL , redis , fastdfs , MongoDB , ZK , 流媒体 , CDN , P2P , K8S , Docker , TCP/IP , 协程 , DPDK , ffmpeg等) , 免费分享

文章插图
4. 收获有两个收获 , 一是创建的pthread线程Join和Detach两种状态下内存处理差别;二是在进程maps中显示线程栈[stack:TID]更有利于调试 。
4.1 pthread线程的join和detach区别《Avoiding memory leaks in POSIX thread programming》讲到如何避免POSIX线程编程时内存泄漏 。
首先pthread_create()创建的线程默认是joinable的 。
对于joinable线程 , 系统会分配私有内存存储线程结束状态、线程栈、线程ID等等资源 。这些资源会一直存在 , 直到线程结束并且线程被其他线程joined 。所以确保joinable线程资源得到释放的两个条件是:线程退出、被其他线程joined 。
对于detached线程 , 如果其退出 , 那么系统会自动回收其占用的资源 。
关于joinable线程没有被其他线程joined造成内存泄漏的实验 。
#include<stdio.h>#include<pthread.h>void run() {pthread_exit(0);}int main () {pthread_t thread;int rc;long count = 0;while(1) {if(rc = pthread_create(&thread, 0, run, 0) ) {printf("ERROR, rc is %d, so far %ld threads createdn", rc, count);perror("Fail:");return -1;}usleep(10);count++;}return 0;}输出结果如下:ERROR, rc is 11, so far 32751 threads createdFail:: Cannot allocate memory总共创建了32571个线程 , 造成内存消耗殆尽 。通过对比中间过程的maps , 可以发现每次增加一个8MB的栈以及一个分隔页 。

文章插图
在pthread_create()之后增加pthread_join()则内存非常稳定 。
#include<stdio.h>#include<pthread.h>void run() {pthread_exit(0);}int main () {pthread_t thread;int rc;long count = 0;while(1) {if(rc = pthread_create(&thread, 0, run, 0) ) {printf("ERROR, rc is %d, so far %ld threads createdn", rc, count);perror("Fail:");return -1;}pthread_join(thread, NULL);usleep(10);count++;}return 0;}借用文档里面一句话总结一下:Joinable threads should be joined during programming. If you are creating joinable threads in your program, don’t forget to call pthread_join(pthread_t, void**) to recycle the private storage allocated to the thread.调用pthread_join()将阻塞线程自己 , 一直等到加入的线程运行结束 。
线程可以分为两种:joined和detached 。并不是所有线程创建后都默认joinable , 需要显式指定属性 。
joinable线程在创建后 , 可以通过pthread_detach()显式分离 。在分离后 , 不可以再合并 。
推荐阅读
- 康熙的和硕二十三公主,和硕和恪公主生了一个公主
- 员工行为准则的详细介绍
- 电影|五一多部大片跑路 电影《珠峰队长》逆流而上:做了一个不理智的决定
- 皇后是不是皇上的第一个老婆,太宗皇后叫什么名字
- 张良在史记中是什么世家,史记留侯世家张良是一个怎样的存在
- C语言预编译处理,如何定义一个带参数 宏?如何取消宏定义?
- 自己搭建一个网站需要多少钱
- 服务器出问题了,作为IT,怎样才能第一个知道?免得被骂
- 刘彻后面一个皇帝是谁母亲是谁,刘彻的母亲王皇后
- 一个被误解的乱世枭雄,一个被误解的星座
