Linux的线程创建限制

来源:互联网 发布:淘宝发v任务要钱吗 编辑:程序博客网 时间:2024/06/09 18:50

导言:现网有个版本上线一段时间后,通过SSH重新登陆时显示Cannot allocate memory错误,结果只能通过重启机器来恢复服务。通过分析发现是新的版本引入一个bug,某个进程会不停地创建新的线程,那么问题是Linux下一个进程可以创建多少个线程,从而会导致这个错误出现。

1 原因分析

问题重现,通过一个测试程序,验证错误是否会重现。

#include <iostream>#include <pthread.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>using namespace std;void* thr_func (void*){    for(;;) sleep(500);    return 0;}void max_thread_test (){    const int MAX = 4194304;    //const int MAX = 10;    int i = 0;    for (; i < MAX; ++i) {        int ret = 0;        pthread_attr_t attr;        pthread_attr_init(&attr);        // detached        ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);        if (ret) {             perror("pthread_attr_setdetachstate err");             exit(1);        }        size_t stacksize = 0;        ret = pthread_attr_getstacksize(&attr, &stacksize);        if (ret) {             perror("pthread_attr_getstacksize err");             exit(1);        } else {            static bool once = true;            if (once) {                std::cout << "default thread stacksize: " << stacksize << std::endl;                once = false;            }        }        // thread stacksize        stacksize = 16384;// 16KB        ret = pthread_attr_setstacksize(&attr, stacksize);        if (ret) {             perror("pthread_attr_setstacksize err");             exit(1);        } else {            static bool once = true;            if (once) {                std::cout << "change thread stacksize to : " << stacksize << std::endl;                once = false;            }        }        if (!(i % (MAX / 10000))) std::cerr << "..." << i;        pthread_t thread;        ret = pthread_create(&thread, &attr, thr_func, NULL);        if (ret) {            std::cerr << "\nthreads created " << i << std::endl ;            perror("pthread_create");            exit(1);        }    }    std::cerr << "threads created " << i - 1 << std::endl ;    std::cout << "exit (succes)" << std::endl;}int main(){    max_thread_test();    for(;;) sleep(5000);    std::cout << "end" << std::endl;    return 0;}/* 在Mac上使用LLVM/Clang编译得到如下结果:$./test_max_thread default thread stacksize: 524288change thread stacksize to : 16384...0...419...838...1257...1676threads created 2047pthread_create: Cannot allocate memory* */

通过max-thread-per-process-in-linux和Maximum number of threads per process in Linux?可以得知,除了内存大小限制外,还有很多内核参数的限制,但理论上一个进程可以创建的最大线程数量为:

number of threads = total virtual memory / stack size

因此,32位系统由于进程的虚拟地址空间为4G,可以创建的线程数量为3G/8M=384个线程,而64位系统的进程可以创建的线程数量为128T/8M=16777216个线程(千万级)。当然在实际使用中一般不会创建这么多线程,因为线程间的切换会占用2000+的CPU时钟周期,可能导致CPU过高。一般会根据CPU核数启用相应的线程数,尽量减少不必要的线程切换。

pic

通过修改下面的参数,可以尽可能地创建更多的线程。

echo 1 > /proc/sys/vm/overcommit_memory echo 1000000 > /proc/sys/kernel/threads-maxecho 10000000 > /proc/sys/vm/max_map_countecho "4194304" > /proc/sys/kernel/pid_max

max_map_count的补充说明:在Linux上测试,创建一次线程操作会调用一次mmap,但是会映射两个地址段(/proc/pid/maps有两行,一个4KB,一个8MB),map_count会累积两次,所以一个进程要满足:创建线程数*2 + 其他的映射地址段数量 < max_map_count

2 Refer

man 5 proc
理解Linux的memory overcommit
Infographics: Operation Costs in CPU Clock Cycles
http://www.kegel.com/c10k.html#limits.threads
https://www.akkadia.org/drepper/glibcthreads.html
https://www.akkadia.org/drepper/nptl-design.pdf
NPTL caps maximum threads at 65528?

0 0
原创粉丝点击