隐蔽的内存泄漏——pthread_create 属性设置不当导致

本文介绍了一个隐蔽的内存泄漏问题,由于pthread_create后未正确释放线程导致内存持续增长。通过设置PTHREAD_CREATE_DETACHED属性,确保线程结束后自动释放资源。

最近解决了一个隐蔽的内存泄漏问题,我们的进程是HA模式,用户不停的切换,会导致内存不停的增长,切换一次,再切回来内存便增加8M左右。原因就是是pthread_create后的僵死线程没有释放导致的内存持续增长。


pthread_create (&thread, NULL, &thread_function, NULL); 就这么写了,参数2没有设置线程结束后自动detach,并且没有使用pthread_join或pthread_detach释放执行结束后线程的空间!

Linux man page 里有已经说明了这个问题:
    When a joinable thread terminates, its memory resources (thread descriptor and stack) are not deallocated until another thread performs pthread_join on it. Therefore, pthread_join must be called  once  for each joinable thread created to avoid memory leaks.

也就说线程执行完后如果不join的话,线程的资源会一直得不到释放而导致内存泄漏!


解决办法


创建线程前设置 PTHREAD_CREATE_DETACHED 属性
 pthread_attr_t attr;
 pthread_t thread;
 thread_attr_init (&attr);
 pthread_attr_setdetachstate (&attrPTHREAD_CREATE_DETACHED);
 pthread_create (&thread, &attr&thread_function, NULL);
 pthread_attr_destroy (&attr);

这样就会在线程return/pthread_exit后释放内存。

其实用valgrind检查时会提示pthread_create没有释放的问题,这样的问题也只有在长时间运行时,慢慢积累这一点点的内存才会暴露出来。



属性值不能直接设置,须使用相关函数进行操作,初始化的函数为pthread_attr_init,这个函数必须在pthread_create函数 之前调用。属性对象主要包括是否绑定、是否分离、堆栈地址、堆栈大小、优先级。默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。

线程的分离状态决定一个线程以什么样的方式来终止自己。在上面的例子中,我们采用了线程的默认属性,即为非分离状态,这种情况下,原有的线程等待 创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其 他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。设置线程分离状态的函数为pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)。


static void *get_spectrum_thread(void *arg) { int sockfd = init_udp_ser(12307); char buffer[4098]; int count = 0; int num = 0; size_t len = 0; struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); parse_spectrum_msg parse_spectrum_data = {0}; size_t sent_len = 0; char data[8192] = {0}; unsigned char *spectrum_char_data = NULL; float spectrum_float_data[4096] = {0}; float spectrum_freq_data[8192] = {0}; float spectrum_dbm_data[8192] = {0}; char *local_array = NULL; while(1) { if (!spectrum_flags) { usleep(20 * 1000); // 等待开启标志 continue; } ssize_t recv_len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &addr_len); if (recv_len < 0) { perror("recvfrom failed"); close(sockfd); exit(EXIT_FAILURE); } if (strlen(buffer) > 0 && strstr(buffer , "RealResult")) { parse_spectrum_json_data(&parse_spectrum_data , buffer); printf("sepctrum_data = %s \r\n", parse_spectrum_data.data); if (parse_spectrum_data.chunk_id == count) { num = parse_spectrum_data.total_chunks; count++; strcat(data , parse_spectrum_data.data); if (num == count) { num = 0; count = 0; spectrum_char_data = base64_decode(data , &len); printf("recv_spectrum_all_data = %s \r\n", data); memcpy(spectrum_float_data , spectrum_char_data , len); free(spectrum_char_data); parse_spectrum_array_data(spectrum_float_data, (len + 3) / 4, spectrum_freq_data, spectrum_dbm_data); spectrum_array = create_json_spectrum_arrays(spectrum_flags, start_freq, end_freq, spectrum_freq_data, len / 8 , spectrum_dbm_data, len / 8); printf("spectrum_array = %s \r\n", spectrum_array); pthread_mutex_unlock(&spectrum_mutex); free(spectrum_array); memset(data , 0 , sizeof(data)); } } else { if (parse_spectrum_data.chunk_id == 0 && parse_spectrum_data.total_chunks == 1) { printf("count = %d \r\n", count); memset(data , 0 , sizeof(data)); spectrum_char_data = base64_decode(parse_spectrum_data.data , &len); memcpy(spectrum_float_data , spectrum_char_data , len); free(spectrum_char_data); parse_spectrum_array_data(spectrum_float_data, (len + 3) / 4, spectrum_freq_data, spectrum_dbm_data); pthread_mutex_lock(&spectrum_mutex); spectrum_array = create_json_spectrum_arrays(spectrum_flags, start_freq, end_freq, spectrum_dbm_data, len / 4 , spectrum_freq_data, len / 4); pthread_mutex_unlock(&spectrum_mutex); free(spectrum_array); memset(data , 0 , sizeof(data)); count = 0; } else if (parse_spectrum_data.chunk_id == 0 && parse_spectrum_data.total_chunks > 1) { memset(data , 0 , sizeof(data)); num = 0; count = 1; strcat(data , parse_spectrum_data.data); } } } usleep(20 * 1000); } 优化这段代码
最新发布
11-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值