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スレッドです。
次の情報を入手しました。これは、ホストプロバイダーによって課せられた制限です。これは、プログラミングやLinuxとは関係ありません。
基盤となるオペレーティングシステム(この場合、Debian Linux)では、プロセスがこれ以上スレッドを作成できません。最大量を上げる方法はこちらをご覧ください: Linuxのプロセスあたりの最大スレッド数?
私のプログラムでは5000スレッド程度を処理する必要があることをインターネットで読みました。
これは、OSに設定された制限、実行中のプロセスの量などに依存します。正しい設定を行うと、その数のスレッドに簡単に到達できます。私は自分のコンピューターでUbuntuを実行しており、単一のJavaプログラムでバックグラウンドで実行されているすべての「通常のもの」で制限に達する前に約32000のスレッドを作成できます(これは行われました無限ループですぐにスリープ状態になるスレッドを作成したばかりのテストプログラムを使用します)当然、実際に何かをしているその大量のスレッドは、おそらくかなり高速にコンシューマハードウェアを停止させます。
同じコマンドをより小さいスタックサイズ「-Xss64k」で試して結果を渡すことはできますか?
「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();
}
}
}
JVMは、スタックまたは他のスレッドごとのメモリの割り当てに失敗します。 _-Xss
_でスタックサイズを小さくすると、OOMが発生する前に作成できるスレッドの数を増やすのに役立ちます(ただし、JVMでは、小さなスタックサイズを任意に設定することはできません)。
これが問題であることを確認するには、_-Xss
_を微調整して作成されたスレッドの数がどのように変化するかを確認するか、JVMで strace を実行します(ほぼ確実にmmap()
例外がスローされる直前にENOMEM
を返します)。
仮想サイズ、つまり_ulimit -v
_のulimit
も確認してください。この制限を大きくすると、同じスタックサイズでより多くのスレッドを作成できます。常駐セットのサイズ制限(_ulimit -m
_)は 現在のLinuxカーネルでは無効 であることに注意してください。
また、_-Xmx
_を小さくすると、スレッドスタック用により多くのメモリを残すことができます。