Pthread_create()和内存泄漏

pthread_create() and memory leaks

本文关键字:内存 泄漏 create Pthread      更新时间:2023-10-16

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

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

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

如果我将线程数增加到10,000,VIRT将增加到70+ gigs,但在50k左右结束,假设我注释掉pthread_exit(NULL)。如果我使用pthread_exit(NULL),它结束时大约113m仍然在VIRT中。这些可以接受吗?托普什么都没告诉我吗?

void* run_thread( void* id )
{
    int thread_id = *(int*)id;
    int count = 0;
    while ( count < 10 ) {
        sleep( 1 );
        printf( "Thread %d at count %dn", 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;
}

我知道这是一个相当古老的问题,但我希望其他人能从中受益。这确实是一个内存泄漏。线程是用默认属性创建的。默认情况下,线程是可接合的。一个可接合的线程保持它的底层记账直到它完成。和加入。如果线程从未连接过,则设置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);

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

main()中调用pthread_exit(0)使主线程在自己退出之前等待所有其他派生线程退出。这可以让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);