Linux, hafızanın yetersiz olup olmadığını sormadan işlemlerimi öldürmeye başlayacak mı?


66

Birkaç yoğun hafıza içeren programı (2-5 GB) arka arkaya çalıştırmak için komutlar içeren bir kabuk betiği çalıştırıyordum. Senaryomun ilerleyişini kontrol etmeye geri döndüğümde Killed, terminalimin bana bildirdiği gibi bazı süreçlerimin olduğunu keşfettiğimde şaşırdım . Birkaç program daha sonra Killedbaşlanan programlardan önce başarılı bir şekilde tamamlanmıştır , ancak daha sonra tüm programlar bir bölümleme hatasında başarısız olmuştur (kodumdaki bir hatadan dolayı olabilir veya olmayabilir), okumaya devam et.

Kullandığım belirli kümenin kullanım geçmişine baktım ve birinin aynı anda birkaç bellek yoğun işlemi gerçekleştirmeye başladığını ve bunu yaparken de kümenin kullanabileceği gerçek belleği (ve muhtemelen takas alanını) tükettiğini gördüm. En iyi anlayabildiğim kadarıyla, bu bellek yoğun işlemler yaklaşık olarak programlarımda sorun yaşamaya başladığımda yayınlanmaya başladı.

Linux'un belleği tükenmeye başladıktan sonra programlarımı öldürmesi mümkün mü? Ve sonradan ortaya çıkan segmentasyon hatalarının, programları çalıştırmak için kullanılabilecek hafıza yetersizliğinden (kodumdaki bir hata yerine) olması mümkün mü?


2
Hafızayı ayırdığınızda, hafızanın başarılı bir şekilde tahsis edilip edilmediğini kontrol etmek için bir ifadeniz var mı? Bu, kodunuzda hata olup olmadığı ya da sistemdeki bellek eksikliğinden kaynaklanıp kaynaklanmadığına dair bir ipucu sağlamalıdır.
unxnut

Yanıtlar:


72

Yapabilir.

Linux'ta karşılaşabileceğiniz iki farklı bellek durumu vardır. Karşılaştığınız değer sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory) değerine bağlıdır

Giriş:
Çekirdek 'bellek aşımı' denilen şeyi gerçekleştirebilir. Bu, çekirdeğin programları gerçekten sistemde olduğundan daha fazla bellek ayırmasıdır. Bu oldukça yaygın bir durum olduğu için programların tahsis ettikleri hafızayı kullanmayacakları umuduyla yapılır.

overcommit_memory = 2

Ayarlandığında overcommit_memory, 2çekirdek hiç fazla işlemez. Bunun yerine, bir programa hafıza tahsis edildiğinde, bu hafızaya sahip olma erişimi sağlanır. Sistem, bir tahsisat talebini yerine getirmek için yeterli boş hafızaya sahip değilse, çekirdek talep için bir hata verecektir. Durumu incelikle ele almak programa kalmış. Gerçekten başarısız olduğunda tahsisin başarılı olduğunu kontrol etmezse, uygulama genellikle bir segfault ile karşılaşır.

Segfault durumunda, aşağıdaki gibi bir çizgi bulmalısınız dmesg:

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

at 0Uygulama (ama tek yol değildir) başarısız bir bellek ayırma çağrı sonucu olabilir başlatılmamış imleç, erişim çalıştı anlamına gelir.

overcommit_memory = 0 ve 1

Ne zaman overcommit_memoryayarlandığında 0veya 1, overcommit etkindir ve programlar gerçekten mevcut olandan daha fazla bellek ayırmaya izin verilir.

Bununla birlikte, bir program belleği kullanmak istediğinde tahsis edilmiştir, ancak çekirdek aslında onu tatmin etmek için yeterli belleğe sahip olmadığını bulur, biraz bellek alması gerekir. İlk olarak, kızarma önbellekleri gibi çeşitli bellek temizleme görevlerini gerçekleştirmeye çalışır, ancak bu yeterli değilse, o zaman bir işlemi sonlandırır. Bu sonlandırma OOM-Katil tarafından gerçekleştirilir. OOM-Killer, hangi programların hangi hafızayı kullandığını, ne kadar süredir çalıştıklarını, bunları kimin çalıştırdığını ve hangisinin öldürüleceğini belirleyen başka faktörleri görmek için sisteme bakar.

İşlem öldükten sonra, kullandığı hafıza boşalır ve hafıza dışı durumuna yeni neden olan program şimdi ihtiyacı olan hafızaya sahiptir.

Ancak, bu modda bile, programlar hala tahsis talepleri reddedilebilir. Ne zaman overcommit_memoryolduğunu 0, çekirdek bu ayırma isteklerini inkar başlamalı zaman en iyi tahminde almaya çalışır. Ayarlandığında 1, bir isteği ne zaman reddetmesi gerektiğini belirlemek için hangi belirlemeyi kullandığından emin değilim, ancak çok büyük istekleri reddedebilir.

OOM-Killer’ın çıktısına bakarak ve aşağıdaki dmesggibi mesajlar bularak karıştığını görebilirsiniz :

[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

Öyle görünüyor ki her iki durum da başıma geldi.
NeutronStar

@Joshua Ben sadece cevabı güncelledi. overcommit_memory0 veya 2 olarak ayarlandığında hala tahsis hatalarını alabileceğinizi söylemeyi unuttum .
Patrick

OOM katilini görev alanına yerleştirmek için bir bağlantı düzenlemek yararlı olabilir.
0xC0000022L

@ 0xC0000022L Teşekkürler, bu iyi bir makale (güncel olmasa da). OOM katilini kontrol etmekle ilgili bir şey koymak istemedim çünkü bu sorunun bir parçası değildi (ve kısa bir konu değil) ve burada bununla ilgili bir sürü başka sorumuz var.
Patrick,

1
@mikeserv OOM katilinin davranışının onu kontrol etmeyle ilgisi olduğunu söylemiyorum. Soru Linux’un programlarını öldürüp öldürmeyeceği idi. Linux'un bunu yapmasını nasıl önleyeceğiniz ilk önce linux'un gerçekten onu yaptığını tespit etmeyi gerektirir. Ve eğer overcommit_memory=2OOM katili bile etkin değilse , kontrol etmenin önemi yoktur. Bununla birlikte, bir kez OOM katili olduğunu belirlediğimizde, burada birçok başka soru ve cevapla kapsanan bir başka konu haline gelir.
Patrick

16

Gerçek şu ki, hangi açıdan bakarsanız bakın, sistemin bellek yöneticisi ya da başka bir şey yüzünden sürecinizin boğulmasına bakmaksızın - bu hala bir hatadır. Sadece hafızada işlemekte olduğunuz tüm verilere ne oldu? Kurtarılmalıydı.

overcommit_memory=Linux OOM yönetimini yapılandırmanın en genel yolu olmasına rağmen , aşağıdakiler gibi işlem başına ayarlanabilir:

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

Kullanılması -17yukarıda dışı bellekten yönetiminden bir süreç hariç tutacaktır. Muhtemelen genel olarak iyi bir fikir değildir, ancak böcek avıysanız bunu yapmak faydalı olabilir - özellikle bunun OOM veya kodunuz olup olmadığını bilmek istiyorsanız . Sayının olumlu şekilde artması, sürecin bir OOM etkinliğinde ölme olasılığını artıracak, bu da düşük bellek durumlarında kodunuzun direncini daha iyi artırmanıza ve gerektiğinde zarif bir şekilde çıkmanıza olanak sağlayacaktır.

OOM işleyicisinin mevcut ayarlarını aşağıdaki gibi işlemlere göre kontrol edebilirsiniz:

cat /proc/$pid/oom_score 

Başka intihara gidebilirsin:

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

Bu, yetersiz bellek durumunda bilgisayarı yeniden başlatmaya ayarlar. XYukarıdakileri, yeniden başlatmadan önce bilgisayarın bir çekirdek panikinden sonra durmasını istediğiniz saniye sayısına ayarlayın . Vahşileş.

Ve eğer bir nedenden ötürü, hoşunuza karar verirseniz, bunu kalıcı kılar:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf

Kullandığım paylaşılan bir küme, diğer kullanıcıların izinleri olmadan yeniden başlatmayı takdir etmeyeceğinden eminim.
NeutronStar

3
@Joshua - Kimsenin hoşuna gideceği konusunda çok ciddi şüphelerim var - Asimov'un robot yasalarına bile meydan okuyor. Diğer taraftan, bahsettiğim gibi, OOM'u işlem başına başka şekilde de yapılandırabilirsiniz. Yani işlem başına kendi tanımlanmış kurallarınıza göre kişisel olarak triyaj yapabilirsiniz. Bu tür bir şey, paylaşılan küme senaryosunda özellikle yararlı olabilir gibi geliyor.
mikeserv
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.