java.lang.OutOfMemoryError: unable to create new native thread的解决思路

早上有同事反馈一个服务无法正常启动,报错如下
Caused by: java.lang.OutOfMemoryError:unable to create new native thread

atjava.lang.Thread.start0(Native Method)

atjava.lang.Thread.start(Thread.java:714)
JVM内存溢出,为啥还无法创建新的本地线程,什么鬼?
其实,Java线程模型是基于操作系统原生线程模型来实现的,Java线程也是映射到操作系统的原生线程之上的,JVM中的一个线程就对应服务器操作系统本身的一个线程,因此如果服务本身创建了很多线程,达到操作系统线程数上限时,JVM中再创建线程就会出现unabe to create new native thread的异常。
我们可以从java.lang.Thread类中的一些方法看出来,比如start0方法(start方法调用的),就是调用native方法来实现的,实质就是使用其他语言比如C和C++来实现启动操作系统的一个线程。这其实也是Java语言跨平台的一个体现(字节码和JVM之外的语言层面的跨平台的体现)。
如果小伙伴了解Java中的同步关键字synchronized,那应该知道该关键字在进行优化之前是重量级锁,重量级的原因就是因为该关键字实现同步的方式是在一个已进入同步块的线程执行完之前,会阻塞后面其他线程的进入,而阻塞和唤醒线程都需要通过从用户态转换到内核态来通过操作系统原生线程来实现的。
了解了Java线程是映射到操作系统原生线程之上之后,这个问题就容易找到解决方案了,既然达到了操作系统的线程数上限,那我们看下线程数上限是多少,能否调大,可以使用ulimit -a查看操作系统一些资源限制的设定,如下
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
pending signals (-i) 1024
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 4096
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
其中max user processes (-u) 4096就是我们要找的,我们可以通过ulimit -u 8192临时调大上限,先让应用能跑起来。
当然,这种临时方法只是短时间的应急方案,我们还是要从应用本身出发,查看应用为什么为开启了这么多线程,比如我们的应用就是因为已经被阿里禁用的Executors的滥用导致,在调整为ThreadPoolExecutor后问题解决了。如果应用确实需要创建这么多线程,可以找系统管理员扩大最大线程数的限制。

发布了14 篇原创文章 · 获赞 3 · 访问量 930

猜你喜欢

转载自blog.csdn.net/sjz88888/article/details/104723373