3年前 (2021-01-14)  jvm |   抢沙发  2655 
文章评分 0 次,平均分 0.0

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.lang.OutOfMemoryError: unable to create new native thread

上面的线程快照来自前面给出的示例的Java VisualVM。这个快照清楚地演示了线程的连续创建。

一旦我们确定存在连续的线程创建,我们就可以捕获应用程序的线程转储,以确定创建线程的源代码:

java.lang.OutOfMemoryError: unable to create new native thread

在上面的快照中,我们可以识别负责创建线程的代码。这为采取适当措施提供了有用的见解。

5. 结论

在本文中,我们了解了java.lang.OutOfMemoryError: unable to create new native thread error,我们发现这是由Java应用程序中创建过多线程引起的。

我们将ExecutorService框架和线程转储分析作为解决此问题的两个有用措施,探索了一些解决和分析错误的解决方案。

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1305.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册