【发布时间】:2014-09-27 14:44:20
【问题描述】:
这个问题似乎被问了很多。我有一些看起来不错的遗留生产代码,直到它开始每天获得更多连接。每个连接都启动了一个新线程。最终,它会耗尽内存并崩溃。
我将回顾多年未处理过的 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 ),它在 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;
}
【问题讨论】:
-
我假设您正在报告您的数字的 valgrind 结果。你可以在
return 0之前在main()中添加pthread_exit(0)吗? -
添加这似乎有助于...无论如何使用 valgrind。 'top' 似乎仍然在说有一些虚拟内存仍在使用中。该程序在启动线程之前有 14k 的 VIRT,现在有 110m。不过,这似乎是静态的。无论线程数是10还是1000,VIRT中的100m都在那里。我想我应该相信valgrind?
-
是的。 valgrind 报告内存问题的原因是在主线程结束之前并非所有线程都已完成。添加
thread_exit()调用解决了这个问题。 -
与内存泄漏无关,但您将同一本地
thread_count变量的地址传递给每个新线程。根据线程启动的速度,它可能会看到正确的值,也可能会看到更新、更高的值。您需要在堆上分配一个新变量以传递给每个子线程,或者使用整数强制转换为(void*)。
标签: c++ multithreading memory-leaks pthreads