“Java.lang.OutOfMemoryError: tidak dapat membuat Thread asli baru”

124

Kami mendapatkan "java.lang.OutOfMemoryError : unable to create new native Thread"pada VM RAM 8GB setelah 32k utas (ps -eLF | grep -c java)

Namun "top" and "free -m" shows 50% free memory available,. JDk 64 bit dan dicoba dengan HotSpot dan JRockit. Server memiliki Linux 2.6.18

Kami juga mencoba OS stack size (ulimit -s)tweaker dan proses max (ulimit -u) batas, limit.conf meningkat tetapi semuanya sia-sia.

Kami juga mencoba hampir semua kemungkinan kombinasi ukuran heap, menjaganya tetap rendah, tinggi, dll.

Script yang kami gunakan untuk menjalankan aplikasi adalah

/opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m -Xss128k -jar JavaNatSimulator.jar /opt/tools/jnatclients/natSimulator.properties

Terima kasih balasannya.

Kami telah mencoba mengedit /etc/security/limits.conf dan ulimit tetapi masih tetap sama

[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
Deepak Tewani
sumber
11
Sistem operasi memiliki batasan jumlah utas yang dapat Anda buat. Mengapa Anda membuat lebih dari 32k utas? Sistem Anda kemungkinan besar tidak memiliki ribuan inti prosesor, membuat begitu banyak utas tidak berguna. Gunakan kumpulan utas ( ExecutorService) sebagai gantinya.
Jesper
Terima kasih balasannya. Kami menggunakan perpustakaan open source dan mencoba memuat pengujian itu. Pustaka sumber terbuka itu membuat begitu banyak utas. Tapi yang saya tidak mengerti, adalah ketika "top" menunjukkan 50% memori bebas lalu mengapa Kesalahan OutOfMemory.
Deepak Tewani
Perpustakaan sumber terbuka yang kami gunakan di Perpustakaan ICE4j
Deepak Tewani
11
OutOfMemoryError tidak selalu berarti ruang heap, atau RAM "umum", telah habis. Dalam kasus ini, jelas bahwa kegagalan itu disebabkan OS tidak memiliki sumber daya untuk mengalokasikan utas tambahan. Memiliki 50% memori bebas tidak relevan dengan kegagalan khusus ini.
Andrzej Doyle
1
Apa sumber daya lain yang diperlukan untuk membuat utas baru. Kami mendapat kesan bahwa jika kami meningkatkan RAM, maka kami mungkin dapat membuat lebih banyak utas. Mohon
pandu

Jawaban:

80

Ini bukan masalah memori meskipun nama pengecualian sangat menyarankannya, tetapi masalah sumber daya sistem operasi. Anda kehabisan utas asli, yaitu berapa banyak utas yang diizinkan oleh sistem operasi untuk digunakan JVM Anda.

Ini adalah masalah yang jarang terjadi, karena Anda jarang membutuhkan sebanyak itu. Apakah Anda memiliki banyak pemijahan benang tanpa syarat di mana benang seharusnya tetapi tidak selesai?

Anda dapat mempertimbangkan untuk menulis ulang menggunakan Callable / Runnables di bawah kendali Executor jika memungkinkan. Ada banyak eksekutor standar dengan berbagai perilaku yang dapat dikontrol kode Anda dengan mudah.

(Ada banyak alasan mengapa jumlah utas dibatasi, tetapi bervariasi dari sistem operasi ke sistem operasi)

Thorbjørn Ravn Andersen
sumber
Terima kasih balasannya. Kami menggunakan pustaka sumber terbuka ICE4j dan mencoba memuat uji itu. Tidak bisakah kita meningkatkan batas utas di OS ketika kita tahu bahwa ada 50% memori yang tersisa di server.
Deepak Tewani
Mungkin, tapi saya pikir itu tidak akan membantu Anda seperti itu. Jika Anda kehabisan sumber daya saat pengujian beban, Anda harus dapat mengontrol apa yang terjadi dalam aplikasi Anda. Mengapa Anda memiliki 32.000 utas aktif sekaligus?
Thorbjørn Ravn Andersen
Kami membuat 11 ribu klien yang menggunakan 32 K utas untuk membaca, menulis data pada soket UDP. Dari 32 K utas ini, 10K utas adalah utas tetap hidup yang digunakan untuk menjaga soket tetap terbuka
Deepak Tewani
Saya yakin masalah ini diselesaikan di server web modern. Juga udp dapat kehilangan paket - alasan apa saja Anda tidak hanya menggunakan server web?
Thorbjørn Ravn Andersen
7
Karena pengecualian OutOfMemory seharusnya diberi nama OutOfResources. Sistem operasi tidak dapat menyediakan sumber daya yang Anda butuhkan. (Dan ternyata saya tidak tahu ice4j)
Thorbjørn Ravn Andersen
14

Saya mengalami masalah yang sama selama uji beban, alasannya adalah karena JVM tidak dapat membuat utas Java baru lebih lanjut. Di bawah ini adalah kode sumber 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);`

Akar penyebab: JVM menampilkan pengecualian ini ketika JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR (sumber daya habis (berarti kehabisan memori)) atau JVMTI_RESOURCE_EXHAUSTED_THREADS (Thread habis).

Dalam kasus saya, Jboss membuat terlalu banyak utas, untuk melayani permintaan, tetapi semua utas diblokir. Karena itu, JVM kehabisan thread juga dengan memori (setiap thread menyimpan memori, yang tidak dirilis, karena setiap thread diblokir).

Menganalisis java thread dumps mengamati hampir 61K utas diblokir oleh salah satu metode kami, yang menyebabkan masalah ini. Di bawah ini adalah bagian dari Thread dump

"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)
Madhu Cheepati
sumber
Bagaimana metode memblokir? Tidak pernah kembali?
Thorbjørn Ravn Andersen
8

Sepertinya OS Anda tidak mengizinkan jumlah utas yang Anda coba buat, atau Anda mencapai beberapa batasan di JVM. Terutama jika itu adalah angka bulat seperti 32k, batas satu jenis atau lainnya adalah penyebabnya.

Apakah Anda yakin Anda benar-benar membutuhkan 32k utas? Sebagian besar bahasa modern memiliki semacam dukungan untuk kumpulan utas yang dapat digunakan kembali - Saya yakin Java juga memiliki sesuatu (seperti ExecutorService, seperti yang disebutkan pengguna Jesper). Mungkin Anda dapat meminta utas dari kumpulan seperti itu, daripada membuat yang baru secara manual.

Theodoros Chatzigiannakis
sumber
1
Terima kasih atas jawabannya Kami menggunakan perpustakaan sumber terbuka ICE4j dan mencoba memuat uji itu. Tidak bisakah kita meningkatkan batas utas di OS ketika kita tahu bahwa ada 50% memori yang tersisa di server.
Deepak Tewani
1
Kami membuat 11 ribu klien yang menggunakan 32 K utas untuk membaca, menulis data pada soket UDP. Dari 32 K utas ini, 10K utas adalah utas tetap hidup yang digunakan untuk menjaga soket tetap terbuka
Deepak Tewani
7

Saya akan merekomendasikan untuk juga melihat Ukuran Tumpukan Benang dan melihat apakah Anda mendapatkan lebih banyak utas yang dibuat. Ukuran Thread Stack default untuk JRockit 1.5 / 1.6 adalah 1 MB untuk VM 64-bit di OS Linux. Utas 32K akan membutuhkan sejumlah besar memori fisik dan virtual untuk memenuhi persyaratan ini.

Cobalah untuk mengurangi Ukuran Stack menjadi 512 KB sebagai titik awal dan lihat apakah itu membantu membuat lebih banyak utas untuk aplikasi Anda. Saya juga merekomendasikan untuk menjelajahi penskalaan horizontal, misalnya membagi pemrosesan aplikasi Anda di lebih banyak mesin fisik atau virtual.

Saat menggunakan VM 64-bit, batas sebenarnya akan bergantung pada ketersediaan memori fisik dan virtual OS serta parameter penyetelan OS seperti ulimitc. Saya juga merekomendasikan artikel berikut sebagai referensi:

OutOfMemoryError: tidak dapat membuat utas asli baru - Masalah Demystified

PH
sumber
5

Jika jvm dimulai melalui systemd, mungkin ada maxTasks per batas proses (tugas sebenarnya berarti utas) di beberapa OS linux.

Anda dapat memeriksa ini dengan menjalankan "status layanan" dan memeriksa apakah ada batas maxTasks. Jika ada, Anda dapat menghapusnya dengan mengedit /etc/systemd/system.conf, menambahkan konfigurasi: DefaultTasksMax = infinity

Clement.Xu
sumber
3

Saya memiliki masalah yang sama karena proses hantu yang tidak muncul saat menggunakan top in bash. Ini mencegah JVM menelurkan lebih banyak utas.

Bagi saya, itu diselesaikan ketika mendaftar semua proses java dengan jps (cukup jalankan jpsdi shell Anda) dan bunuh mereka secara terpisah menggunakan kill -9 pidperintah bash untuk setiap proses hantu.

Ini mungkin membantu dalam beberapa skenario.

mac7
sumber
2

Anda memiliki kesempatan untuk menghadapi java.lang.OutOfMemoryError: Unable to create new native threadkapan pun JVM meminta utas baru dari OS. Setiap kali OS yang mendasarinya tidak dapat mengalokasikan utas asli baru, OutOfMemoryError ini akan dilempar. Batas pasti untuk utas asli sangat bergantung pada platform, oleh karena itu disarankan untuk mencari tahu batas tersebut dengan menjalankan pengujian yang mirip dengan contoh tautan di bawah ini. Namun secara umum penyebab situasi java.lang.OutOfMemoryError: Unable to create new native threadmelalui tahapan sebagai berikut:

  1. Utas Java baru diminta oleh aplikasi yang berjalan di dalam JVM
  2. Kode asli JVM memproksikan permintaan untuk membuat utas asli baru ke OS OS mencoba membuat utas asli baru yang membutuhkan memori untuk dialokasikan ke utas
  3. OS akan menolak alokasi memori asli karena ukuran proses Java 32-bit telah menghabiskan ruang alamat memorinya - misalnya (2-4) batas ukuran proses GB telah tercapai - atau memori virtual OS telah sepenuhnya habis
  4. Java.lang.OutOfMemoryError: Tidak dapat membuat kesalahan utas asli baru dilempar.

Referensi: https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread

Sazzad Hissain Khan
sumber
2

Untuk menemukan proses mana yang membuat utas coba:

ps huH

Saya biasanya mengarahkan output ke file dan menganalisis file secara offline (apakah jumlah utas untuk setiap proses seperti yang diharapkan atau tidak)

pengguna8521771
sumber
1

Jika Job Anda gagal karena OutOfMemmory pada node, Anda dapat mengubah jumlah max map dan reducer dan JVM memilih untuk masing-masing node. mapred.child.java.opts (default adalah 200Xmx) biasanya harus ditingkatkan berdasarkan perangkat keras spesifik node data Anda.

Tautan ini mungkin bisa membantu ... tolong periksa

Pavan Kumar K
sumber
1
Kita semua sudah mencoba perubahan yang diberikan pada tautan itu. Tapi hasilnya sama :(
Deepak Tewani
1

konfigurasi JBoss Anda memiliki beberapa masalah, /opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m Xms dan Xmx membatasi penggunaan memori JBoss Anda, ke nilai yang dikonfigurasi, jadi dari 8Gb yang Anda miliki server hanya menggunakan 512M + beberapa tambahan untuk tujuannya sendiri, tingkatkan jumlah itu, ingatlah untuk meninggalkan beberapa gratis untuk OS dan hal-hal lain yang berjalan di sana dan mungkin Anda menjalankannya meskipun ada kode yang tidak menyenangkan. Memperbaiki kode juga akan menyenangkan, jika Anda bisa.

pengguna3390284
sumber
1

Kesalahan ini dapat muncul karena dua alasan berikut:

  • Tidak ada ruang di memori untuk menampung utas baru.

  • Jumlah utas melebihi batas Sistem Operasi.

Saya ragu bahwa jumlah utas telah melebihi batas untuk proses java

Jadi kemungkinan besar masalahnya adalah karena memori. Satu hal yang perlu dipertimbangkan adalah

utas tidak dibuat dalam heap JVM. Mereka dibuat di luar heap JVM. Jadi jika ada sedikit ruang tersisa di RAM, setelah alokasi heap JVM, aplikasi akan menjalankan "java.lang.OutOfMemoryError: tidak dapat membuat utas asli baru".

Solusi yang mungkin adalah mengurangi memori heap atau meningkatkan ukuran ram secara keseluruhan

Maverick
sumber
0

Saya memiliki masalah yang sama dan ternyata itu adalah penggunaan yang tidak tepat dari API java. Saya menginisialisasi pembangun dalam metode pemrosesan batch yang seharusnya tidak dimulai lebih dari sekali.

Pada dasarnya saya melakukan sesuatu seperti:

for (batch in batches) {
    process_batch(batch)
}

def process_batch(batch) {
    var client = TransportClient.builder().build()
    client.processList(batch)
}

ketika saya seharusnya melakukan ini:

for (batch in batches) {
    var client = TransportClient.builder().build()
    process_batch(batch, client)
}

def process_batch(batch, client) {
    client.processList(batch)
}
anthonybell
sumber
-4

Pertama-tama saya tidak akan menyalahkan OS / VM sebanyak itu .. melainkan pengembang yang menulis kode yang membuat begitu banyak Thread . Pada dasarnya di suatu tempat di kode Anda (atau pihak ke-3) banyak utas dibuat tanpa kontrol .

Tinjau stacktraces / kode dengan hati-hati dan kendalikan jumlah utas yang dibuat. Biasanya aplikasi Anda tidak memerlukan thread dalam jumlah besar, jika memang masalahnya berbeda.

Flueras Bogdan
sumber
10
Ini bukanlah solusi untuk pertanyaan tersebut.
ftrujillo