1. 介绍
在本教程中,我们将讨论java.lang.OutOfMemoryError: unable to create new native thread error
无法创建新的本机线程错误。
2. 了解问题
2.1. 问题的原因
大多数Java应用程序本质上是多线程的,由多个组件组成,执行特定的任务,并在不同的线程中执行。但是,底层操作系统(OS)对Java应用程序可以创建的最大线程数设置了上限。
当JVM向底层操作系统请求一个新线程时,JVM抛出“无法创建新的本机线程”错误,而操作系统无法创建新的内核线程(也称为操作系统线程或系统线程)。
事件顺序如下:
1. 在Java虚拟机(JVM)中运行的应用程序请求新线程
2. JVM本机代码向操作系统发送一个创建新内核线程的请求
3. 操作系统试图创建一个需要内存分配的新内核线程
4. 操作系统拒绝本机内存分配,因为
- 请求的Java进程已耗尽其内存地址空间
- 操作系统耗尽了它的虚拟内存
5. 然后Java进程返回java.lang.OutOfMemoryError: unable to create new native thread error
2.2. 线程分配模型
操作系统通常有两种类型的线程:用户线程(由Java应用程序创建的线程)和内核线程。在内核线程之上支持用户线程,内核线程由操作系统管理。
它们之间有三种共同的关系:
1. 多对一 – 多个用户线程映射到单个内核线程
2. 一对一 – 一个用户线程映射到一个内核线程
3. 多对多 – 多个用户线程多路复用到更小或相等数量的内核线程
3. 再现错误
通过在连续循环中创建线程,然后让线程等待,我们可以轻松地重新创建此问题:
while (true) {
new Thread(() -> {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
由于我们将每个线程保持一个小时,同时不断创建新的线程,因此我们将很快达到操作系统的最大线程数。
4. 解决
解决此错误的一种方法是在操作系统级别增加线程限制配置。
但是,这不是一个理想的解决方案,因为OutOfMemoryError可能表示编程错误。让我们看看解决这个问题的其他方法。
4.1. 利用Executor服务框架
利用Java的executor
服务框架进行线程管理可以在一定程度上解决这个问题。默认的executor
服务框架或自定义executor
配置可以控制线程的创建。
我们可以使用Executors.newFixedThreadPool
方法设置一次可使用的最大线程数:
ExecutorService executorService = Executors.newFixedThreadPool(5);
Runnable runnableTask = () -> {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
// Handle Exception
}
};
IntStream.rangeClosed(1, 10)
.forEach(i -> executorService.submit(runnableTask));
assertThat(((ThreadPoolExecutor) executorService).getQueue().size(), is(equalTo(5)));
在上面的示例中,我们首先创建一个固定线程池,其中包含五个线程和一个可运行任务,该任务使线程等待一小时。然后,我们向线程池提交十个这样的任务,并断言有五个任务在executor
服务队列中等待。
因为线程池有五个线程,所以它在任何时候最多可以处理五个任务。
4.2. 捕获和分析线程转储
捕获和分析线程转储有助于了解线程的状态。
让我们看一个线程转储示例,看看可以学到什么:
上面的线程快照来自前面给出的示例的Java VisualVM。这个快照清楚地演示了线程的连续创建。
一旦我们确定存在连续的线程创建,我们就可以捕获应用程序的线程转储,以确定创建线程的源代码:
在上面的快照中,我们可以识别负责创建线程的代码。这为采取适当措施提供了有用的见解。
5. 结论
在本文中,我们了解了java.lang.OutOfMemoryError: unable to create new native thread error
,我们发现这是由Java应用程序中创建过多线程引起的。
我们将ExecutorService
框架和线程转储分析作为解决此问题的两个有用措施,探索了一些解决和分析错误的解决方案。
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1305.html
暂无评论