Linux程序设计中由线程使用不当引起的内存泄漏
2013-01-10 16:31
225 查看
Linux程序设计中由线程使用不当引起的内存泄漏
作者:吴亮
Linux程序设计中,创建线程时调用pthread_create()函数,该函数原型如下:
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void*),
void *arg);
其中第二个参数attr为线程属性指针,一般情况下,我们创建线程时,若对线程属性没有特殊要求,都将此参数设为NULL。这也就使用了线程的默认属性——非分离状态(joinable,或称可接合状态)。之后,主线程必须在适当的时候调用pthread_join(),来接合(join,或等待,同步)子线程,同时释放线程本身占用的资源。否则,线程资源将驻留内存,直到整个进程退出为止,若进程会不断的创建线程,则每创建一次线程都会导致内存资源的消耗,很明显,这样就会构成内存泄漏!
关于这个问题,本人查到了一些佐证:
(1)Linux manpage里是这样讲的:
When a joinable threadterminates, its memory resources (thread descriptor and stack) are notdeallocated until another thread performs pthread_join on it. Therefore,pthread_join must be called once for each joinable thread created to avoid memory leaks.
(2)《Linux高级编程》里是这样讲的:
可接合(非分离态的,需要等待)的线程,就像一个进程一样,当它执行结束时,并没有被GNU/Linux自动清理,而它的退出状态却仍在系统内挂着(这有点像僵尸进程),直到另一个线程调用pthread_join()获取其返回值时,其资源才被释放。
* * * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
对于线程资源的释放,有两种实现方法:
(1)调用pthread_join()
线程创建时,默认属性是可接合的(joinable),那就需要主线程来等待,所以在创建这个线程后适当的时候就必须调用pthread_join()来等待子线程结束执行,否则就会引起内存泄漏!
在调用pthread_create()开线程后,若线程属性是joinable,则必须调用pthread_join()来等待子线程结束执行,这是 Linux同步主线程和子线程的一个机制,但是,这并不等于说,我要在pthread_create()开线程后立即调用pthread_join()来等待该线程结束执行,的确,那样的话跟你用普通函数调用来实现是没有区别的,你完全可以在pthread_create()开线程后去做别的事情,等你觉得应该等待该线程结束执行时再调用pthread_join()。这就是说,假如你的线程采用了默认属性joinable,你就必须在适当的时候调用pthread_join()来同步主线程和子线程,同时释放子线程的资源(线程描述符和堆栈,threaddescriptor
and stack)。
假如你用了默认线程属性,即线程属性为joinable,而又没有在适当的时候调用pthread_join(),那么该线程所占用的资源便不会被释放(kind of like azombie process),因此造成内存泄漏。
(2)将线程属性设为分离状态(detached)
假如你不想或没有必要同步主线程和子线程,那么就把子线程属性设置为detached分离状态,那么子线程结束执行后会自行销毁其占用的资源。
将线程属性设为分离状态(detached),这样,子线程就属于自我销毁那种,子线程函数启动后跟主线程不再有"父子"关系(等待和被等待),退出线程时其资源会释放。注意:创建线程时,若属性参数为NULL,则线程属性默认为可接合的(joinable,即需要主线程等待的)。
可以在线程创建时将其属性设为分离状态(detached),也可在线程创建后将其属性设为分离的(detached)。
* * * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
下面给出分离态和非分离态线程创建的代码框架:
(1)使用线程默认属性创建线程的代码框架
(2)将线程属性设为detached的两种方法的代码框架
作者:吴亮
Linux程序设计中,创建线程时调用pthread_create()函数,该函数原型如下:
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void*),
void *arg);
其中第二个参数attr为线程属性指针,一般情况下,我们创建线程时,若对线程属性没有特殊要求,都将此参数设为NULL。这也就使用了线程的默认属性——非分离状态(joinable,或称可接合状态)。之后,主线程必须在适当的时候调用pthread_join(),来接合(join,或等待,同步)子线程,同时释放线程本身占用的资源。否则,线程资源将驻留内存,直到整个进程退出为止,若进程会不断的创建线程,则每创建一次线程都会导致内存资源的消耗,很明显,这样就会构成内存泄漏!
关于这个问题,本人查到了一些佐证:
(1)Linux manpage里是这样讲的:
When a joinable threadterminates, its memory resources (thread descriptor and stack) are notdeallocated until another thread performs pthread_join on it. Therefore,pthread_join must be called once for each joinable thread created to avoid memory leaks.
(2)《Linux高级编程》里是这样讲的:
可接合(非分离态的,需要等待)的线程,就像一个进程一样,当它执行结束时,并没有被GNU/Linux自动清理,而它的退出状态却仍在系统内挂着(这有点像僵尸进程),直到另一个线程调用pthread_join()获取其返回值时,其资源才被释放。
* * * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
对于线程资源的释放,有两种实现方法:
(1)调用pthread_join()
线程创建时,默认属性是可接合的(joinable),那就需要主线程来等待,所以在创建这个线程后适当的时候就必须调用pthread_join()来等待子线程结束执行,否则就会引起内存泄漏!
在调用pthread_create()开线程后,若线程属性是joinable,则必须调用pthread_join()来等待子线程结束执行,这是 Linux同步主线程和子线程的一个机制,但是,这并不等于说,我要在pthread_create()开线程后立即调用pthread_join()来等待该线程结束执行,的确,那样的话跟你用普通函数调用来实现是没有区别的,你完全可以在pthread_create()开线程后去做别的事情,等你觉得应该等待该线程结束执行时再调用pthread_join()。这就是说,假如你的线程采用了默认属性joinable,你就必须在适当的时候调用pthread_join()来同步主线程和子线程,同时释放子线程的资源(线程描述符和堆栈,threaddescriptor
and stack)。
假如你用了默认线程属性,即线程属性为joinable,而又没有在适当的时候调用pthread_join(),那么该线程所占用的资源便不会被释放(kind of like azombie process),因此造成内存泄漏。
(2)将线程属性设为分离状态(detached)
假如你不想或没有必要同步主线程和子线程,那么就把子线程属性设置为detached分离状态,那么子线程结束执行后会自行销毁其占用的资源。
将线程属性设为分离状态(detached),这样,子线程就属于自我销毁那种,子线程函数启动后跟主线程不再有"父子"关系(等待和被等待),退出线程时其资源会释放。注意:创建线程时,若属性参数为NULL,则线程属性默认为可接合的(joinable,即需要主线程等待的)。
可以在线程创建时将其属性设为分离状态(detached),也可在线程创建后将其属性设为分离的(detached)。
* * * * * * * * * * * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
下面给出分离态和非分离态线程创建的代码框架:
(1)使用线程默认属性创建线程的代码框架
#include <pthread.h> void* thread_function (void* thread_arg) { /* Do work here... */ pthread_exit(“Exiting from the thread_function!”); } int main () { pthread_t thr; void* thread_result; pthread_create (&thr, NULL, &thread_function, NULL); /* Do other work here... */ /* The second thread must be joined by the initial(calling) thread before exit or elsewhere to avoid MEMORY LEAKS */ pthread_join(thr, &thread_result); return 0; } |
方法一,在线程创建时,通过属性变量设置 |
#include <pthread.h> void* thread_function (void* thread_arg) { /* Do work here... */ pthread_exit(….); } int main () { pthread_attr_t attr; pthread_t thread; pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); pthread_create (&thread, &attr, &thread_function, NULL); pthread_attr_destroy (&attr); /* Do work here... */ /* No need to join the second thread. */ return 0; } |
方法二:线程创建后,通过调用pthread_detach()来设置 |
注意: 如果thread_function()做的工作足够少的话,在pthread_create()返回线程ID前,thread_function()可能就已经结束了,而这个线程ID可能又被系统分配给了新创建的线程,假如新线程不打算使用分离态,那下面的pthread_detach()调用就会引起错乱,实际上原来要设为分离态的线程并没有设为分离态,假如再没有调用pthread_join()的话(实际上也不会,因为调用了pthread_detach()就不该再调用pthread_join(),而且此时join的实际上是新线程),那就会导致该线程的资源不被释放,而又引起内存泄露。所以在这儿,pthread_detach()的调用还是需要综合考量的。 |
#include <pthread.h> void* thread_function (void* thread_arg) { /* Do work here... */ pthread_exit(….); } int main () { pthread_t thread; pthread_create (&thread, NULL, &thread_function, NULL); pthread_detach(thread); /* Do work here... */ /* No need to join the second thread. */ return 0; } |
相关文章推荐
- Linux 程序设计中由线程使用不当引起的内存泄露
- Hashset 使用不当引起的内存泄漏
- ABMultiValueCopyLabelAtIndex使用不当引起的内存泄漏
- 无比奇怪的问题,Runtime报错,程序仍可运行(有可能是线程崩溃,但主程序不崩溃,线程崩溃可能是因为锁使用不当引起的)
- ABMultiValueCopyLabelAtIndex使用不当引起的内存泄漏
- 使用IntrospectorCleanupListener 解决quartz引起的内存泄漏
- Linux线程创建以及回调函数的使用
- 为什么linuxC程序设计中不能使用system("cd ..")来改变当前工作路径而用chdir()函数
- 使用IntrospectorCleanupListener 解决quartz引起的内存泄漏
- UIPopover使用不当引起的crash解决
- 并行程序设计简介-使用Intel TBB线程库
- linux程序设计——取消一个线程(第十二章)
- 使用IntrospectorCleanupListener 解决quartz引起的内存泄漏
- pthread_cancel引起线程死锁-linux
- 在Linux中使用线程
- Android 非UI线程使用View.post()方法一处潜在的内存泄漏
- Linux系统下C语言编程:线程的创建和使用
- 在linux下使用用Valgrind查找内存泄漏和无效内存访问(转载)
- 在Linux中使用线程与线程的合并与分离
- Android 非UI线程使用View.post()方法一处潜在的内存泄漏