Akankah Linux mulai mematikan proses saya tanpa bertanya apakah memori menjadi pendek?

66

Saya sedang menjalankan skrip shell dengan perintah untuk menjalankan beberapa program intensif-memori (2-5 GB) back-to-back. Ketika saya kembali untuk memeriksa kemajuan skrip saya, saya terkejut menemukan bahwa beberapa proses saya Killed, seperti terminal saya melaporkan kepada saya. Beberapa program telah berhasil diselesaikan sebelum program yang kemudian Killeddimulai, tetapi semua program kemudian gagal dalam kesalahan segmentasi (yang mungkin atau mungkin bukan karena bug dalam kode saya, terus membaca).

Saya melihat sejarah penggunaan cluster tertentu yang saya gunakan dan melihat bahwa seseorang mulai menjalankan beberapa proses intensif-memori pada saat yang sama dan dalam melakukannya menghabiskan memori nyata (dan mungkin bahkan ruang swap) yang tersedia untuk cluster. Sebisa mungkin, proses intensif-memori ini mulai berjalan pada waktu yang sama ketika saya mulai mengalami masalah dengan program saya.

Apakah mungkin Linux membunuh program saya setelah kehabisan memori? Dan mungkinkah kesalahan segmentasi yang saya dapatkan nantinya adalah karena kurangnya memori yang tersedia untuk menjalankan program saya (bukan bug dalam kode saya)?

Bintang neutron
sumber
2
Ketika Anda mengalokasikan memori, apakah Anda memiliki pernyataan untuk memeriksa apakah memori tersebut berhasil dialokasikan? Itu harus memberikan petunjuk apakah ada bug dalam kode Anda atau apakah itu karena kurangnya memori dalam sistem.
unxnut

Jawaban:

72

Bisa.

Ada dua kondisi memori yang berbeda yang dapat Anda temui di Linux. Yang Anda temui tergantung pada nilai sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

Pendahuluan:
Kernel dapat melakukan apa yang disebut 'memory overcommit'. Ini adalah saat kernel mengalokasikan program lebih banyak memori daripada yang sebenarnya ada dalam sistem. Ini dilakukan dengan harapan bahwa program tidak akan benar-benar menggunakan semua memori yang mereka alokasikan, karena ini adalah kejadian yang cukup umum.

overcommit_memory = 2

Ketika overcommit_memorydiatur ke 2, kernel tidak melakukan overcommit sama sekali. Alih-alih ketika suatu program dialokasikan memori, dijamin akses untuk memiliki memori itu. Jika sistem tidak memiliki cukup memori bebas untuk memenuhi permintaan alokasi, kernel hanya akan mengembalikan kegagalan untuk permintaan tersebut. Terserah program untuk menangani situasi dengan anggun. Jika tidak memeriksa apakah alokasi berhasil ketika benar-benar gagal, aplikasi akan sering menemui segfault.

Dalam kasus segfault, Anda harus menemukan garis seperti ini di output dmesg:

[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]

The at 0berarti bahwa aplikasi mencoba mengakses pointer diinisiasi, yang dapat hasil dari gagal panggilan alokasi memori (tetapi bukan satu-satunya cara).

overcommit_memory = 0 dan 1

Ketika overcommit_memorydiatur ke 0atau 1, overcommit diaktifkan, dan program diizinkan untuk mengalokasikan lebih banyak memori daripada yang sebenarnya tersedia.

Namun, ketika sebuah program ingin menggunakan memori yang telah dialokasikan, tetapi kernel menemukan bahwa itu sebenarnya tidak memiliki cukup memori untuk memenuhinya, itu perlu mendapatkan beberapa memori kembali. Pertama mencoba untuk melakukan berbagai tugas pembersihan memori, seperti pembilasan cache, tetapi jika ini tidak cukup maka akan menghentikan proses. Pemutusan ini dilakukan oleh OOM-Killer. OOM-Killer melihat sistem untuk melihat program apa yang menggunakan memori apa, berapa lama mereka telah berjalan, siapa yang menjalankannya, dan sejumlah faktor lain untuk menentukan mana yang terbunuh.

Setelah proses itu terbunuh, memori yang digunakannya dibebaskan, dan program yang hanya menyebabkan kondisi kehabisan memori sekarang memiliki memori yang dibutuhkan.

Namun, bahkan dalam mode ini, program masih dapat ditolak permintaan alokasi. Ketika overcommit_memoryadalah 0, kernel mencoba untuk mengambil perkiraan terbaik ketika harus mulai menyangkal permintaan alokasi. Ketika diatur ke 1, saya tidak yakin tekad apa yang digunakannya untuk menentukan kapan harus menolak permintaan tetapi bisa menolak permintaan yang sangat besar.

Anda dapat melihat apakah Pembunuh OOM terlibat dengan melihat output dari dmesg, dan menemukan pesan seperti:

[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB
Patrick
sumber
Jadi, sepertinya kedua situasi itu terjadi pada saya.
NeutronStar
@ Joshua, saya baru saja memperbarui jawabannya. Saya lupa menyebutkan Anda masih bisa mendapatkan kegagalan alokasi ketika overcommit_memorydiatur ke 0 atau 2.
Patrick
Saya pikir mengedit tautan ke Menjinakkan pembunuh OOM ke dalam pos mungkin bermanfaat.
0xC0000022L
@ 0xC0000022L Terima kasih, itu artikel yang bagus (meskipun sedikit ketinggalan zaman). Saya tidak ingin meletakkan apa pun tentang mengendalikan pembunuh OOM karena itu bukan bagian dari pertanyaan (dan itu bukan topik pendek), dan kami punya banyak pertanyaan lain di sini tentang hal itu.
Patrick
1
@ mikeserv Saya tidak mengatakan bahwa perilaku pembunuh OOM tidak ada hubungannya dengan mengendalikannya. Pertanyaannya adalah apakah linux akan mematikan programnya. Cara mencegah linux dari melakukan hal itu terlebih dahulu memerlukan menetapkan bahwa itu memang linux yang melakukannya. Dan jika overcommit_memory=2, pembunuh OOM bahkan tidak diaktifkan, jadi mengendalikannya tidak relevan. Namun begitu kami menetapkan bahwa itu adalah pembunuh OOM, yang menjadi topik lain yang dibahas oleh banyak pertanyaan & jawaban lainnya di sini.
Patrick
16

Yang benar adalah bahwa terlepas dari cara Anda melihatnya - apakah proses Anda tersendat karena manajer memori sistem atau karena sesuatu yang lain - itu masih bug. Apa yang terjadi dengan semua data yang baru saja Anda proses di memori? Seharusnya sudah disimpan.

Walaupun overcommit_memory=merupakan cara paling umum untuk mengkonfigurasi manajemen OOM Linux, ini juga dapat disesuaikan untuk setiap proses seperti:

echo [-+][n] >/proc/$pid/oom_adj

Penggunaan -17di atas akan mengecualikan proses dari manajemen kehabisan memori. Mungkin bukan ide yang bagus secara umum, tetapi jika Anda melakukan pencarian bug, itu bisa bermanfaat - terutama jika Anda ingin tahu apakah itu OOM atau kode Anda. Menambah jumlah secara positif akan membuat proses lebih mungkin untuk dibunuh dalam acara OOM, yang dapat memungkinkan Anda untuk lebih meningkatkan ketahanan kode Anda dalam situasi memori rendah dan untuk memastikan Anda keluar dengan anggun ketika diperlukan.

Anda dapat memeriksa pengaturan OOM handler saat ini per proses seperti:

cat /proc/$pid/oom_score 

Jika tidak, Anda bisa bunuh diri:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X

Itu akan mengatur komputer untuk reboot jika terjadi kondisi kehabisan memori. Anda mengatur hal di Xatas ke jumlah detik yang Anda ingin komputer berhenti setelah panik kernel sebelum reboot. Menjadi liar.

Dan jika, karena suatu alasan, Anda memutuskan Anda menyukainya, buatlah itu tetap:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf
mikeserv
sumber
Ini adalah kluster bersama yang saya gunakan, saya yakin pengguna lain tidak akan menghargainya restart tanpa persetujuan mereka.
NeutronStar
3
@ Joshua - Saya ragu dengan sangat serius bahwa ada orang yang akan menyukainya - itu bahkan menentang hukum robotika Asimov. Di sisi lain, seperti yang saya sebutkan, Anda dapat mengkonfigurasi OOM per proses dengan cara lain juga. Artinya, Anda dapat melakukan triase secara pribadi berdasarkan aturan yang Anda tentukan per proses. Hal semacam itu kedengarannya mungkin sangat berguna dalam skenario cluster bersama.
mikeserv