32Kスレッド後の8GB RAM VMで"Java.lang.OutOfMemoryError : unable to create new native Thread
"を取得します(ps -eLF | grep -c Java)
ただし、"top" and "free -m" shows 50% free memory available
。 JDkは64ビットで、HotSpotとJRockitの両方で試した。サーバーにはLinux 2.6.18がある。
OS stack size (ulimit -s)
の調整とmax process(ulimit -u)の制限、limit.confの増加も試みましたが、すべて無駄でした。
また、可能な限り多くのヒープサイズの組み合わせを試してみました。
アプリケーションを実行するために使用するスクリプトは、
/opt/jrockit-jdk1.6/bin/Java -Xms512m -Xmx512m -Xss128k -jar JavaNatSimulator.jar /opt/tools/jnatclients/natSimulator.properties
返信いただきありがとうございます。
/etc/security/limits.confとulimitを編集してみましたが、それでも同じことが言えます
[root@jboss02 ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 72192
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 65535
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) 72192
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
例外名が強く示唆していても、これはメモリの問題ではありませんが、オペレーティングシステムのリソースの問題です。ネイティブスレッド、つまりオペレーティングシステムがJVMで使用できるスレッド数が不足しています。
あなたがめったにそのような多くを必要としないので、これは珍しい問題です。あなたは、スレッドがどこで終わるべきであるが終わらない、無条件スレッド生成をたくさん持っていますか?
可能であれば、Executorの制御下でCallable/Runnablesを使用するように書き直すことを検討してください。コードで簡単に制御できるさまざまな動作を持つ標準エグゼキュータがたくさんあります。
(スレッド数が制限される理由はたくさんありますが、オペレーティングシステムによって異なります)
ロードテスト中に同じ問題が発生しました。その理由は、JVMがそれ以上新しいJavaスレッドを作成できないためです。以下はJVMのソースコードです。
if (native_thread->osthread() == NULL) {
// No one should hold a reference to the 'native_thread'.
delete native_thread;
if (JvmtiExport::should_post_resource_exhausted()) {
JvmtiExport::post_resource_exhausted(
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR |
JVMTI_RESOURCE_EXHAUSTED_THREADS,
"unable to create new native thread");
} THROW_MSG(vmSymbols::Java_lang_OutOfMemoryError(), "unable to create new native thread");
} Thread::start(native_thread);`
根本的な原因:JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR(リソースが使い果たされた(メモリが使い果たされた))またはJVMTI_RESOURCE_EXHAUSTED_THREADS(スレッドが使い果たされた)の場合、JVMはこの例外をスローします。
私の場合、Jbossはリクエストを処理するには多すぎるスレッドを作成していますが、すべてのスレッドがブロックされています。このため、JVMはメモリだけでなくスレッドも使い果たします(各スレッドはメモリを保持していますが、各スレッドはブロックされているため解放されません)。
Javaスレッドダンプを分析したところ、約61Kのスレッドが、この問題の原因となっている私たちの方法の1つによってブロックされていることがわかりました。以下はスレッドダンプの一部です
"SimpleAsyncTaskExecutor-16562" #38070 prio=5 os_prio=0 tid=0x00007f9985440000 nid=0x2ca6 waiting for monitor entry [0x00007f9d58c2d000]
Java.lang.Thread.State: BLOCKED (on object monitor)
お使いのOSが、作成しようとしているスレッドの数を許可していないか、JVMの制限を超えている可能性があります。特にそれが32kのようなラウンド数であるならば、何らかの種類の制限は非常にありそうな犯人です。
本当に32Kスレッドが必要ですか。最近のほとんどの言語は、再利用可能なスレッドのプールを何らかの形でサポートしています。Javaも同様に適切な場所にあります(Jesper氏が言ったようにExecutorService
のように)。手動で新しいスレッドを作成するのではなく、おそらくそのようなプールからスレッドを要求できます。
Thread Stack Sizeも調べて、もっとスレッドが作成されるかどうかを確認することをお勧めします。 JRockit 1.5/1.6 のデフォルトのスレッドスタックサイズは、Linux OSの64ビットVMの場合、1 MBです。 32Kスレッドでは、この要件を満たすために大量の物理メモリと仮想メモリが必要になります。
出発点として512 KBにスタックサイズを減らしてみて、それがアプリケーション用のスレッドの作成に役立つかどうかを確認してください。私はまた水平方向のスケーリングを検討することをお勧めします。アプリケーション処理を複数の物理マシンまたは仮想マシンに分割する。
64ビットVMを使用している場合、実際の制限はOSの物理メモリと仮想メモリの可用性、およびulimitcなどのOSチューニングパラメータによって異なります。参考として、次の記事もお勧めします。
Bashでtopを使用しても表示されないゴーストプロセスが原因で、私は同じ問題を抱えていました。これにより、JVMがさらにスレッドを生成するのを防ぎました。
私にとっては、 jps (シェルでjps
を実行するだけ)ですべてのJavaプロセスをリストアップし、それぞれのghostプロセスに対してkill -9 pid
bashコマンドを使用してそれらを別々にkillしたときに解決しました。
これはいくつかのシナリオで役立つかもしれません。
JVMがOSから新しいスレッドを要求するたびにJava.lang.OutOfMemoryError: Unable to create new native thread
に直面する機会があります。基盤となるOSが新しいネイティブスレッドを割り当てることができないときはいつでも、このOutOfMemoryErrorがスローされます。ネイティブスレッドの厳密な制限は非常にプラットフォームに依存するため、以下のリンクの例のようにテストを実行してこれらの制限を見つけることをお勧めします。しかし、一般的に、Java.lang.OutOfMemoryError: Unable to create new native thread
を引き起こす状況は以下の段階を経ていきます。
参照: https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread
/opt/jrockit-jdk1.6/bin/Java -Xms512m -Xmx512m XmsとXmxはJBossのメモリ使用量を設定値に制限しているため、8Gbからは512Mしか使用できません。 +自分自身の目的のために余分なものを増やし、その数を増やし、そこで走っているOSや他のもののためにいくらか自由にしておくのを忘れないでください。可能であれば、コードの修正もいいでしょう。
ノード上のOutOfMemmoryが原因でJobが失敗した場合は、maxマップとリデューサーの数を微調整し、それぞれにJVMが選択できます。 mapred.child.Java.opts(デフォルトは200Xmx)は通常、データノード固有のハードウェアに基づいて増やす必要があります。
このリンク 参考になるかもしれません... pls check
私はこれと同じ問題を抱えていましたが、それはJava APIの不適切な使い方であることがわかりました。私はビルダーをバッチ処理メソッドで初期化していましたが、それは複数回初期化されることは想定されていませんでした。
基本的に私は以下のようなことをしていました:
for (batch in batches) {
process_batch(batch)
}
def process_batch(batch) {
var client = TransportClient.builder().build()
client.processList(batch)
}
私がこれをすべきだったとき:
for (batch in batches) {
var client = TransportClient.builder().build()
process_batch(batch, client)
}
def process_batch(batch, client) {
client.processList(batch)
}
Jvmがsystemdを介して起動された場合、一部のLinux OSではプロセスあたりのmaxTasks制限(タスクは実際にはスレッドを意味する)があるかもしれません。
これを確認するには、 "service status"を実行し、maxTasks制限があるかどうかを確認します。ある場合は、/etc/systemd/system.confを編集してconfigを追加して削除できます。DefaultTasksMax = infinity
このエラーは、次の2つの理由で表面化する可能性があります。
新しいスレッドを収容するためのスペースがメモリにありません。
スレッド数がオペレーティングシステムの制限を超えています。
スレッド数がJavaプロセスの制限を超えたことは疑いありません
そのため、おそらくメモリが原因で問題が発生している可能性があります。
スレッドはJVMヒープ内に作成されません。それらはJVMヒープの外側で作成されます。そのため、JVMヒープの割り当て後、RAMに残っているスペースが少ないと、アプリケーションは「Java.lang.OutOfMemoryError:新しいネイティブスレッドを作成できません」となります。
考えられる解決策は、ヒープメモリを減らすか、全体的なRAMサイズを増やすことです。
どのプロセスがスレッドを作成しているのかを調べるには、次のようにします。
ps huH
私は通常、出力をファイルにリダイレクトし、そのファイルをオフラインで分析します(各プロセスのスレッド数は予想通りかどうかはわかりません)。