Java.Lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません

Suraj P 2023年10月12日
  1. Java で新しいネイティブ スレッド エラーを作成できない
  2. java.lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません を解決する方法
  3. まとめ
Java.Lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません

この記事では、Java の java.lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません エラーについて学習します。

Java で新しいネイティブ スレッド エラーを作成できない

Java で構築された実際のアプリケーションのほとんどは、本質的にマルチスレッドであり、さまざまなタスクを実行する多くのコンポーネントがあります。 これらのタスクは、スループットを向上させるために異なるスレッドで実行されます。 ただし、Java アプリケーションが作成できるスレッドの最大数は、使用しているオペレーティング システム (OS) によって異なります。

そのため、オペレーティング システムが新しいカーネル スレッド (システム スレッドまたは OS スレッドとも呼ばれる) を作成できない場合は常に、Java 仮想マシン (JVM) によって新しいネイティブ スレッドを作成できませんというエラーがスローされます。

バックエンドで次のイベントが発生し、このエラーが発生します。

  1. JVM 内のプログラム/アプリケーションがオペレーティング システムに新しいスレッドを要求します。
  2. JVM ネイティブ コードによって新しいカーネル スレッドを作成する要求が OS に送信されます。
  3. オペレーティング システムは、メモリ割り当て手順を含む新しいスレッドを作成しようとします。
  4. 仮想メモリが OS によって使い果たされているか、要求元の Java アプリケーションによってメモリ アドレス空間が使い果たされているため、オペレーティング システムはメモリを割り当てることができません。
  5. JVM が新しいネイティブ スレッドを作成できませんというエラーをスローします。

それをよりよく理解するために例を見てみましょう。

import java.util.concurrent.TimeUnit;

public class Test {
  public static void main(String[] args) {
    while (true) {
      new Thread(() -> {
        try {
          TimeUnit.HOURS.sleep(1);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }).start();
    }
  }
}

上のコードでは、無限ループを利用してスレッドを作り続けて待機させていますが、1時間スレッドを保持したまま作り続けているため、OSが許容する最大スレッド数にすぐに達してしまいます。

java.lang.OutOfMemoryError: 新しいネイティブ スレッドを作成できません を解決する方法

では、このエラーを解決するにはどうすればよいですか、または回避策はありますか?

1つの解決策は、OS レベルで設定を変更して許可されるスレッドの数を増やすことですが、この解決策は 2つの理由で実行できません。

  1. まず、OS レベルでの再構成は容易ではなく、推奨されません。
  2. 2 番目に、ほとんどの場合、OS スレッドの制限とは関係ありません。 プログラミングエラーがあるためにエラーが発生します。 たとえば、上記のプログラムでは、理想的な方法ではない無限ループを使用して連続的に作成しています。

別の解決策または回避策は、ExecutorService フレームワークを使用して、特定の時間に処理できるスレッド プール内のスレッド数を制限することです。

例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class Test {
  public static void main(String[] args) {
    ExecutorService es = Executors.newFixedThreadPool(10);

    Runnable tasks = () -> {
      try {
        TimeUnit.HOURS.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    };

    IntStream.rangeClosed(1, 15).forEach(x -> es.submit(tasks));
  }
}

コードでは、最大 10 個のスレッドを持つことができる固定サイズのスレッド プールを作成し、スレッドを 1 時間待機させる Runnable タスクを作成しました。

IntStream を使用して、15 個のタスクをスレッド プールに送信したため、10 個が送信され、残りの 5 個は ExecutorService キューに置かれます。

まとめ

この記事では、Java で新しいネイティブ スレッドを作成できませんというエラーが発生するのは、オペレーティング システムが新しいカーネル スレッドを作成できない場合であることを学びました。 また、ExecutorService フレームワークを使用したソリューションまたは回避策も検討しました。

著者: Suraj P
Suraj P avatar Suraj P avatar

A technophile and a Big Data developer by passion. Loves developing advance C++ and Java applications in free time works as SME at Chegg where I help students with there doubts and assignments in the field of Computer Science.

LinkedIn GitHub

関連記事 - Java Error