异常信息说明
异常消息java.lang.OutOfMemoryError:Unable to create new native thread
无法创建新的本机线程意味着Java应用程序已经达到了可以启动的线程数量的限制。
那是什么原因造成了这个异常呢?
当底层操作系统无法分配新的线程,将抛出此OutOfMemoryError,线程的申请数量非常依赖于操作系统平台,因此后面会通过实例来测试,机器本身支持的线程数量
异常出现场景
通常有几个场景会造成此类问题:
由JVM中运行的应用程序请求新的Java线程
JVM native代码向操作系统申请创建新的本地线程的请求
操作系统尝试创建一个新的本机线程,需要将内存分配给线程
由于32位Java进程大小已耗尽其内存地址空间,因此操作系统将拒绝本地内存分配
那么如何解决这个问题呢?
其实可以通过增加操作系统级别的限制来绕过Unable创建新的本机线程问题,比如如果限制了JVM可以在用户空间中生成的进程数,那么应该检出并可能增加限制,max user processes选项
ulimit简介:ulimit 用于限制 shell 启动进程所占用的资源,支持以下各种类型的限制:所创建的内核文件的大小、进程数据块的大小、Shell 进程创建文件的大小、内存锁住的大小、常驻内存集的大小、打开文件描述符的数量、分配堆栈的最大大小、CPU 时间、单个用户的最大线程数、Shell 进程所能使用的最大虚拟内存。同时,它支持硬资源和软资源的限制。
ulimit各选项说明:
core file size (blocks, -c) 0 #core文件的最大值为100 blocks。
data seg size (kbytes, -d) unlimited #进程的数据段可以任意大。
scheduling priority (-e) 0
file size (blocks, -f) unlimited #文件可以任意大。
pending signals (-i) 98304 #最多有98304个待处理的信号。
max locked memory (kbytes, -l) 32 #一个任务锁住的物理内存的最大值为32KB。
max memory size (kbytes, -m) unlimited #一个任务的常驻物理内存的最大值。
open files (-n) 1024 #一个任务最多可以同时打开1024的文件。
pipe size (512 bytes, -p) 8 #管道的最大空间为4096字节。
POSIX message queues (bytes, -q) 819200 #POSIX的消息队列的最大值为819200字节。
real-time priority (-r) 0
stack size (kbytes, -s) 10240 #进程的栈的最大值为10240字节。
cpu time (seconds, -t) unlimited #进程使用的CPU时间。
max user processes (-u) 98304 #当前用户同时打开的进程(包括线程)的最大个数为98304。
virtual memory (kbytes, -v) unlimited #没有限制进程的最大地址空间。
file locks (-x) unlimited #所能锁住的文件的最大个数没有限制。
代码重现异常
测试代码,max user processes当前值为11808
结论
虽然可以通过ulimit来增加可创建线程数量,但是还需要通过评估机器本身性能和单个线程的内存分配量来合理设置ulimit参数。同时代码层面需要重新审视是否真正需要创建大量线程,才能从根本上解决问题。
参考:
https://plumbr.io/outofmemoryerror/unable-to-create-new-native-thread
http://man.linuxde.net/ulimit