java.lang.OutOfMemoryError: Unable to create new native thread
没有一样东西是可以随便挥霍的,亲情、爱情都不行。JVM 也不行!
程序也都是和现实世界规律一致的。Java 中存在多线程,支持同时执行多项任务。所以物理机上即使只有一个CPU,我们也可以同时运行多个程序。
JVM 中的线程也需要内存空间来执行自己的任务。如果线程数量太多就会把相应的内存空间给消耗完,引出新的问题!
JVM 向操作系统申请创建新的 native thread(原生线程)时,就有可能会碰到 java.lang.OutOfMemoryError: Unable to create new native thread 错误。如果底层操作系统创建新的 native thread 失败,JVM 就会抛出相应的 OutOfMemoryError。
java.lang.OutOfMemoryError: Unable to create new native thread 错误的场景大多是这样产生的:
- Java 程序向 JVM 请求创建一个新的Java线程;
- JVM 本地代码(native code)代理该请求,尝试创建一个操作系统级别的 native thread(原生线程);
- 操作系统尝试创建一个新的 native thread,需要同时分配一些内存给该线程;
- 如果操作系统的虚拟内存已耗尽,或者是受到 32 位进程的地址空间限制(约2-4GB),OS就会拒绝本地内存分配;
- 然后 JVM 就会抛出 java.lang.OutOfMemoryError: Unable to create new native thread 错误。
所以说产生 java.lang.OutOfMemoryError: Unable to create new native thread 错误的具体原因就是:程序创建的线程数量已达到上限值。
下面我们来一段代码,自己利用程序产生一个 java.lang.OutOfMemoryError: Unable to create new native thread 错误。
while(true){
new Thread(new Runnable(){
public void run() {
try {
Thread.sleep(10000000);
} catch(InterruptedException e) { }
}
}).start();
}
利用死循环创建 N 多个新线程。相信用不了多久,就会产生 java.lang.OutOfMemoryError: Unable to create new native thread 错误。
原生线程的数量由具体环境决定。如果你想测试出不同系统的极限在哪里就可以使用上面的示例代码在不同的操作系统上进行测试!
有时候我们通过可以修改系统限制来避开 Unable to create new native thread 问题。
ulimit -a
似乎是 max user processes 数不足?那我们将它放大一倍试一试!
ulimit -u 2048
但是根据我的经验来说,产生 java.lang.OutOfMemoryError: Unable to create new native thread 问题,大多都是因为你的程序有问题。你的程序可能创建了成千上万的线程,但是没有几个程序可以 Hold 住上万个线程的。
那么该怎么排查这类问题呢?
可以通过 jstack 确定应用创建了多少线程?超量创建的线程的堆栈信息是怎样的?谁创建了这些线程?一旦明确了这些问题,便很容易解决。
关于 jstack 使用的案例,可以参考我的这篇文章《详解使用 jstack 跟踪 java 异常代码》。这篇文章中的图片,由于交不起钱,七牛云中的外链都失效了,大家凑合着看吧!
其实我们有一个公式,可以大致的计算出程序能创建的线程数。这个公式如下:
(MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Number of threads
这 4 个内存相关的参数,我解释一下:
- MaxProcessMemory:指的是一个进程的最大内存
- JVMMemory:JVM内存
- ReservedOsMemory:保留的操作系统内存
- ThreadStackSize:线程栈的大小
根据这个公式,我们能大致的判断出是不是系统参数设置的问题!
参考资料
本文由 创作,采用 知识共享署名4.0 国际许可协议进行许可。本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为: 2021/04/20 10:14