web-dev-qa-db-ja.com

Javaメモリエラー:新しいネイティブスレッドを作成できません

Javaサーバーを実行しているときに、UNIXサーバーでこのエラーが発生します。

Exception in thread "Thread-0" Java.lang.OutOfMemoryError: unable to create new native thread
at Java.lang.Thread.start0(Native Method)
at Java.lang.Thread.start(Thread.Java:640)
at [... where ever I launch a new Thread ...]

約600のスレッドが実行されているたびに発生します。

サーバーでこの変数を設定しました:

$> ulimit -s 128

私にとって奇妙に見えるのは、このコマンドの結果です。前回バグが発生したときに実行しました。

$> free -m
              total       used       free     shared    buffers     cached
Mem:          2048        338       1709          0          0          0
-/+ buffers/cache:        338       1709
Swap:            0          0          0

Javaサーバーを次のように起動します。

$> /usr/bin/Java -server -Xss128k -Xmx500m -jar /path/to/myJar.jar

私のdebianバージョン:

$> cat /etc/debian_version
5.0.8

My Javaバージョン:

$> Java -version
Java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)

私の質問:私のプログラムは5000スレッド程度を処理すべきだとインターネットで読んだことがあります。それで、何が起こっており、どのように修正するのですか?


編集:これは、シェルを開いたときのulimit -aの出力です。

core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 794624
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 100000
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 794624
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

スクリプトをinit.dからデーモンとして実行しますが、これは私が実行するものです:

DAEMON=/usr/bin/Java
DAEMON_ARGS="-server -Xss128k -Xmx1024m -jar /path/to/myJar.jar"
ulimit -s 128 && ulimit -n 10240 && start-stop-daemon -b --start --quiet --chuid $USER -m -p $PIDFILE --exec $DAEMON -- $DAEMON_ARGS \
    || return 2

編集2:Javaスレッドのテスト: how-many-threads-can-a-Java-vm-support でこのスタックオーバーフローの質問に遭遇しました

    public class DieLikeADog { 
        private static Object s = new Object(); 
        private static int count = 0; 
        public static void main(String[] argv){ 
            for(;;){ 
                new Thread(new Runnable(){ 
                        public void run(){ 
                            synchronized(s){ 
                                count += 1; 
                                System.err.println("New thread #"+count); 
                            } 
                            for(;;){ 
                                try { 
                                    Thread.sleep(100); 
                                } catch (Exception e){ 
                                    System.err.println(e); 
                                } 
                            } 
                        } 
                    }).start(); 
            } 
        } 
    } 

私のサーバーでは、613スレッド後にプログラムがクラッシュします。これは正常ではなく、サーバー構成にのみ関連していると確信しています。誰でも助けてくれますか?


編集3:私はこの記事と他の多くの人に出会いました Linuxは1000スレッドを作成できません ですが、皆さんはあなたのシステムでそれができると言っています。分かりません。

また、サーバーでこのスクリプトを実行しました: threads_limits.c 制限は約620スレッドです。

私のウェブサイトは現在オフラインであり、これは私のプロジェクトに起こりうる最悪の事態です。 glibcなどを再コンパイルする方法がわかりません。作業が多すぎます。

Windowsサーバーに切り替える必要があると思います。このページで提案されている設定はいずれも変更を加えていないため、システムの制限は、関係するプログラムに関係なく、600〜620スレッドです。

25
Joel

次の情報を入手しました。これは、ホストプロバイダーによって課せられた制限です。これは、プログラミングやLinuxとは関係ありません。

12
Joel

基盤となるオペレーティングシステム(この場合、Debian Linux)では、プロセスがこれ以上スレッドを作成できません。最大量を上げる方法はこちらをご覧ください: Linuxのプロセスあたりの最大スレッド数?

私のプログラムでは5000スレッド程度を処理する必要があることをインターネットで読みました。

これは、OSに設定された制限、実行中のプロセスの量などに依存します。正しい設定を行うと、その数のスレッドに簡単に到達できます。私は自分のコンピューターでUbuntuを実行しており、単一のJavaプログラムでバックグラウンドで実行されているすべての「通常のもの」で制限に達する前に約32000のスレッドを作成できます(これは行われました無限ループですぐにスリープ状態になるスレッドを作成したばかりのテストプログラムを使用します)当然、実際に何かをしているその大量のスレッドは、おそらくかなり高速にコンシューマハードウェアを停止させます。

7
esaj

同じコマンドをより小さいスタックサイズ「-Xss64k」で試して結果を渡すことはできますか?

3
souser

「Native Posix Thread Library」が欠落していると思われ始めています。

>getconf GNU_LIBPTHREAD_VERSION

次のような出力が必要です。

NPTL 2.13

そうでなければ、Debianのインストールは台無しになります。私はそれを修正する方法がわかりませんが、Ubuntu Serverのインストールは良い動きのようです...

for ulimit -n 100000; (open fd:s)次のプログラムは32.000スレッド程度を処理できるはずです。

それを試してみてください:

package test;

import Java.io.InputStream;
import Java.net.ServerSocket;
import Java.net.Socket;
import Java.util.ArrayList;
import Java.util.concurrent.Semaphore;

public class Test {

    final static Semaphore ss = new Semaphore(0);


    static class TT implements Runnable {

        @Override
        public void run() {
            try {
                Socket t = new Socket("localhost", 47111);
                InputStream is = t.getInputStream();
                for (;;) {
                    is.read();
                }

            } catch (Throwable t) {
                System.err.println(Thread.currentThread().getName() + " : abort");
                t.printStackTrace();
                System.exit(2);
            }

        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {

            Thread t = new Thread() {
                public void run() {
                    try {
                        ArrayList<Socket> sockets = new ArrayList<Socket>(50000);
                        ServerSocket s = new ServerSocket(47111,1500);
                        ss.release();

                        for (;;) {
                            Socket t = s.accept();
                            sockets.add(t);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.exit(1);

                    }
                }
            };


            t.start();
            ss.acquire();


            for (int i = 0; i < 30000; i++) {

                Thread tt = new Thread(new TT(), "T" + i);
                tt.setDaemon(true);
                tt.start();
                System.out.println(tt.getName());
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    return;
                }
            }

            for (;;) {
                System.out.println();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    return;
                }
            }

        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}
2
KarlP

JVMは、スタックまたは他のスレッドごとのメモリの割り当てに失敗します。 _-Xss_でスタックサイズを小さくすると、OOMが発生する前に作成できるスレッドの数を増やすのに役立ちます(ただし、JVMでは、小さなスタックサイズを任意に設定することはできません)。

これが問題であることを確認するには、_-Xss_を微調整して作成されたスレッドの数がどのように変化するかを確認するか、JVMで strace を実行します(ほぼ確実にmmap()例外がスローされる直前にENOMEMを返します)。

仮想サイズ、つまり_ulimit -v_のulimitも確認してください。この制限を大きくすると、同じスタックサイズでより多くのスレッドを作成できます。常駐セットのサイズ制限(_ulimit -m_)は 現在のLinuxカーネルでは無効 であることに注意してください。

また、_-Xmx_を小さくすると、スレッドスタック用により多くのメモリを残すことができます。

1
Adam Zalcman