pthread_create()和内存泄漏

时间:2014-08-05 02:32:51

标签: c++ multithreading memory-leaks pthreads

这个问题似乎被问了很多。我有一些看似很好的遗留生产代码,直到它每天开始获得更多连接。每个连接都启动了一个新线程。最终,它会耗尽内存并崩溃。

我要回到pthread(和C套接字),这是我多年没有处理过的。我的教程内容丰富,但是当我使用top时,我看到同样的事情。所有线程退出,但仍有一些虚拟内存占用。 Valgrind告诉我调用pthread_create()时可能会丢失内存。最基本的示例代码如下。

最可怕的部分是,当所有线程都退出时,pthread_exit(NULL)似乎在VIRT中留下了大约100米的空间。如果我注释掉这条线,那就更适合居住了,但还是有一些。在我的系统上,它以大约14k开始,以47k结束。

如果我将线程数增加到10,000,那么VIRT会上升到70+演出,但是在假设我注释掉pthread_exit(NULL)的情况下完成大约50k。如果我使用pthread_exit(NULL),它仍然在VIRT中完成大约113m。这些可以接受吗?顶级没有告诉我一切吗?

void* run_thread( void* id )
{
    int thread_id = *(int*)id;
    int count = 0;
    while ( count < 10 ) {
        sleep( 1 );
        printf( "Thread %d at count %d\n", thread_id, count++ );
    }

    pthread_exit( NULL );
    return 0;
}

int main( int argc, char* argv[] )
{
    sleep( 5 ); 
    int thread_count    = 0;
    while( thread_count < 10 ) {
        pthread_t my_thread;
        if ( pthread_create( &my_thread, NULL, run_thread, (void*)&thread_count ) < 0 )   {
            perror( "Error making thread...\n" );
            return 1;
        }

        pthread_detach( my_thread );
        thread_count++;
        sleep( 1 );
    }

    pthread_exit( 0 );  // added as per request
    return 0;
}

2 个答案:

答案 0 :(得分:4)

在您编辑将pthread_exit(0)添加到main()的末尾之前,您的程序将在所有线程完成运行之前完成执行。 valgrind因此报告了程序终止时仍然处于活动状态的线程仍然保留的资源,使得程序看起来像内存泄漏。

pthread_exit(0)中对main()的调用使主线程在其自身退出之前等待所有其他生成的线程退出。这使得valgrind可以在内存利用率方面观察到干净的运行。

(我假设linux是你的操作系统,但是你的评论似乎正在运行各种各样的UNIX。)

你看到的额外虚拟内存只是linux为你的程序分配一些页面,因为它是一个大内存用户。只要您的驻留内存利用率很低并且在达到空闲状态时保持不变,并且虚拟利用率相对恒定,您就可以假设您的系统运行良好。

默认情况下,每个线程在linux上获得2MB的堆栈空间。如果每个线程堆栈不需要那么多空间,您可以通过初始化pthread_attr_t并使用pthread_attr_setstacksize()将其设置为较小的堆栈大小来调整它。适当的堆栈大小取决于函数调用堆栈的增长深度以及这些函数的局部变量占用的空间。

#define SMALLEST_STACKSZ PTHREAD_STACK_MIN
#define SMALL_STACK (24*1024)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, SMALL_STACK);
/* ... */
pthread_create(&my_thread, &attr, run_thread, (void *)thread_count);
/* ... */
pthread_attr_destroy(&attr);

答案 1 :(得分:3)

我知道这是一个相当古老的问题,但我希望其他人会受益。 这确实是内存泄漏。使用默认属性创建线程。默认情况下,线程是可连接的。一个可连接的线程保持其基础簿记,直到它完成...并加入。 如果从未加入线程,请设置de Detached属性。一旦线程终止,将释放所有(线程)资源。 这是一个例子:

pthread_attr_t attr;
pthread_t thread;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, 1);
pthread_create(&thread, &attr, &threadfunction, NULL);
pthread_attr_destroy(&attr);