OOM系列之五:java.lang.OutOfMemoryError: 无法创建新的本地线程问题详解转载
此文来自于plumbr官网,plumbr作为一个常用的JVM 监测工具,官网有完整的oom和gc文章,准备慢慢全部翻译过来:
第一篇:java.lang.OutOfMemoryError:Java heap space
第二篇:Java.lang.OutOfMemoryError: GC overhead limit exceeded
第三篇:java.lang.OutOfMemoryError: 永久空间
第四篇:java.lang.OutOfMemoryError: 元空间
第五篇:java.lang.OutOfMemoryError: 无法创建新的本地线程
正文:
Java 应用程序本质上是多线程的。这意味着用 Java 编写的程序可以同时(表面上)做几件事。例如——即使在只有一个处理器的机器上——当您将内容从一个窗口拖到另一个窗口时,在后台播放的电影不会因为您一次执行多项操作而停止。
考虑线程的一种方法是将它们视为可以向其提交任务以执行的工人。如果您只有一名工人,他或她当时只能执行一项任务。但是,当您拥有十几个工人时,他们可以同时执行您的多个命令。
现在,与物理世界中的工人一样,JVM 中的线程需要一些肘部空间来执行他们被召唤来处理的工作。当线程多于内存空间时,我们已经为问题奠定了基础:
消息java.lang.OutOfMemoryError: Unable to create new native thread意味着Java 应用程序已达到它可以启动的线程数限制。
1,什么原因造成的?
您有机会遇到java.lang.OutOfMemoryError: Unable to create new native thread每当 JVM 向操作系统请求新线程时。每当底层操作系统无法分配新的本机线程时,就会抛出此 OutOfMemoryError。本机线程的确切限制非常依赖于平台,因此我们建议通过运行类似于以下示例的测试来找出这些限制。但是,一般情况下,导致java.lang.OutOfMemoryError: Unable to create new native thread 的情况会经历以下几个阶段:
- 运行在 JVM 中的应用程序请求一个新的 Java 线程
- JVM 本机代码将创建新本机线程的请求代理到操作系统
- 操作系统尝试创建一个新的本地线程,该线程需要为线程分配内存
- 操作系统将拒绝本机内存分配,因为 32 位 Java 进程大小已耗尽其内存地址空间 - 例如 (2-4) GB 进程大小限制已达到 - 或操作系统的虚拟内存已完全耗尽
- 该java.lang.OutOfMemoryError:无法创建新的本地线程引发错误。
2,举个例子
以下示例在循环中创建并启动新线程。运行代码时,会快速达到操作系统限制并显示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();
}
确切的本机线程限制取决于平台,例如在 Windows、Linux 和 Mac OS X 上的测试表明:
- 64 位 Mac OS X 10.9,Java 1.7.0_45 – JVM 在 #2031 线程创建后终止
- 64 位 Ubuntu Linux,Java 1.7.0_45 – JVM 在 #31893 线程创建后终止
- 64 位 Windows 7、Java 1.7.0_45 – 由于操作系统使用的线程模型不同,此错误似乎不会在此特定平台上引发。在线程 #250,000 上,即使交换文件已增长到 10GB 并且应用程序面临极端的性能问题,该进程仍处于活动状态。
因此,请确保通过调用一个小测试了解自己的限制,并找出何时会触发java.lang.OutOfMemoryError: Unable to create new native thread
3,解决方案
有时,您可以通过增加操作系统级别的限制来绕过无法创建新的本机线程问题。例如,如果您限制了 JVM 可以在用户空间中产生的进程数,您应该检查并可能增加限制:
[root@dev ~]# ulimit -a
核心文件大小(块,-c)0
--- 为简洁起见 ---
最大用户进程 (-u) 1800
通常情况下,OutOfMemoryError 对新本地线程的限制表明存在编程错误。当您的应用程序产生数千个线程时,很可能出现了严重错误——没有多少应用程序可以从如此大量的线程中受益。
解决问题的一种方法是开始进行线程转储以了解情况。你通常会花几天的时间来做这件事。我们的建议是将Plumbr连接到您的应用程序,以找出导致问题的原因以及如何在几分钟内解决它。