Çöplemeye neden olan bir işlemi hızlı bir şekilde nasıl durdurabilirim (fazla bellek ayırma nedeniyle)?


19

Hepimiz bunu yaşadık - bazı programlardan büyük miktarda bellek gerektiren bir şey yapmaları istenir. Bu hafızayı tümüyle tahsis etmeye çalışır ve sistem hemen çöker, durmadan takas eder ve halsiz veya yanıt vermez hale gelir.

Son zamanlarda gülünç derecede büyük bir matris ayırmaya çalışan bir Matlab komut dosyası nedeniyle Ubuntu dizüstü bilgisayarımda bunu yaşadım. ~ 5 + dakika süren çöküşten sonra, Ctrl-F1'i bir konsola gönderip Matlab'ı öldürdüm. Bana derhal sistemin kontrolünü verecek ve rahatsız edici süreci öldürmeme izin verecek bir kısayol anahtarım olmasını tercih ederim; ya da belki de böyle büyük bir tampon tahsis etmeyi sessizce reddetmek.

  1. Aşırı değiştirmeden dolayı yanıt vermeyen veya aşırı halsiz hale gelen bir Linux sisteminin kontrolünü yeniden kazanmanın en hızlı yolu nedir?

  2. Bu tür bir takasın ilk etapta meydana gelmesini önlemenin etkili bir yolu var mı, örneğin bir işlemin ayırmaya çalışmasına izin verilen bellek miktarını sınırlayarak?

Yanıtlar:


12

İşlemi en fazla belleği kullanarak öldürmek için Alt-SysRq-F tuşlarına basın :

  • SysRq tuşu genellikle Yazdır tuşuyla eşlenir.
  • Eğer bir grafik masaüstü kullanıyorsanız, basın gerekebilir Ctrl-Alt-SysRq-F basarak durumda Alt-SysRq başka bir eylem (örneğin anlık programı) tetikler.
  • Dizüstü bilgisayar kullanıyorsanız, bir işlev tuşuna da basmanız gerekebilir.
  • Daha fazla bilgi için wikipedia makalesini okuyun .

5

Bu amaçla bir senaryo hazırladım - https://github.com/tobixen/thrash-protect

Ben iyi bir üretim sunucuları, iş istasyonları ve dizüstü bilgisayarlarda çalışan bu komut dosyası vardı. Bu komut dosyası işlemleri öldürmez, ancak geçici olarak askıya alır - daha sonra bu basit komut dosyası olmasaydı daralma nedeniyle kontrolü kaybettiğimden emin olduğum birkaç durum yaşadım. "En kötü" durumda, sorunlu işlem çok yavaşlatılacak ve sonunda çekirdek (OOM) tarafından öldürülecek, "en iyi" durumda, sorunlu işlem aslında tamamlanacak ... her durumda sunucu veya iş istasyonu durumu araştırmanın kolay olması için nispeten duyarlı kalacaktır.

Tabii ki, "daha fazla bellek satın al" veya "takas kullanma" iki farklı, daha geleneksel cevaptır. "Çökmeyi önlemek nasıl?" Sorusudur, ancak genel olarak çok iyi çalışmazlar Önemsiz olmak, sahte bir süreç ne kadar yüklü olursa olsun tüm hafızayı yiyebilir ve tamponlama / önbellekleme için yeterli hafıza olmadığında bile takas olmadan da çöp sorunlarına girebilir). Thrash-korumalı artı çok fazla takas alanı öneriyorum.


Değiştirmeyi devre dışı bırakma hakkında, unix.stackexchange.com/a/24646/9108'e göre en iyi seçenek olmayabilir.
sashoalm

Gerçekten, birisi bana da aynı şeyi yaptı, bu yüzden o noktada thrash-korumalı dokümanı değiştirdim.
tobixen

4
  1. Aşırı değiştirmeden dolayı yanıt vermeyen veya aşırı halsiz hale gelen bir Linux sisteminin kontrolünü yeniden kazanmanın en hızlı yolu nedir?

Yukarıda Alt-SysRq-F ile daha önce yanıtlanmış

  1. Bu tür bir takasın ilk etapta meydana gelmesini önlemenin etkili bir yolu var mı, örneğin bir işlemin ayırmaya çalışmasına izin verilen bellek miktarını sınırlayarak?

Bu 2. bölüme cevap veriyorum. Evet, ulimithala tek bir işlemi sınırlayacak kadar iyi çalışıyor. Yapabilirsin:

  • muhtemelen kontrolden çıkacağını bildiğiniz bir işlem için yumuşak bir sınır belirleyin
  • ekstra sigorta istiyorsanız tüm süreçler için kesin bir limit belirleyin

Ayrıca, kısaca belirtildiği gibi:

Kaynak kullanımını sınırlamak ve bu tür sorunları önlemek için CGroup'ları kullanabilirsiniz

Gerçekten de, cgroups daha gelişmiş kontrol sunuyor, ancak şu anda yapılandırmak daha karmaşık.

Eski okul ulimit

Bir kez kapalı

Heres basit bir örnek:

$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)

O:

  • 1 GB'lık genel bellek kullanımı için yumuşak bir sınır belirler (ulimit, kB biriminde sınırı varsayar)
  • r2(){ r2 $@$@;};r2 r2Yığın hafızası isterken CPU ve RAM'i katlanarak kendiliğinden iki katına çıkaracak şekilde özyinelemeli bash işlev çağrısı çalıştırır .

Gördüğünüz gibi, 1GB'den fazlasını talep etmeye çalışırken durdu.

Not, -vsanal bellek ayırma üzerinde çalışır (toplam, yani fiziksel + takas).

Kalıcı koruma

Sanal bellek ayırmayı sınırlamak için for aseşdeğeridir .-vlimits.conf

Herhangi bir tek hatalı davranış sürecine karşı korumak için aşağıdakileri yapıyorum:

  • Tüm işlemler için bir sabit adres alanı sınırı belirleyin.
  • address space limit = <physical memory> - 256MB.
  • Bu nedenle, açgözlü bellek kullanımı veya etkin bir döngü ve bellek sızıntısı olan tek bir işlem TÜM fiziksel belleği tüketemez.
  • 256 MB tavan boşluğu, ssh veya bir konsol ile gerekli işlemler için mevcuttur.

Bir astar:

$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"

Doğrulamak için bu aşağıdakilerle sonuçlanır (örn. 16GB sistemde):

$ cat /etc/security/limits.d/mem.conf
*   hard    as      16135196
$ ulimit -H -v
161351960

Notlar:

  • Yalnızca bellek kullanımıyla birlikte tek bir işleme geçmeye karşı hafifletir.
  • Ağır bellek basıncına sahip çok işlemli bir iş yükünün daralmaya neden olmasını engellemeyecektir (o zaman cevap gruplarıdır).
  • rssSınırlar.conf dosyasında seçeneği kullanmayın . Daha yeni çekirdekler tarafından saygı duyulmaz.
  • Muhafazakar.
    • Teorik olarak, bir süreç spekülatif olarak çok fazla bellek talep edebilir, ancak sadece aktif olarak bir altkümeyi (daha küçük çalışma kümesi / yerleşik bellek kullanımı) kullanabilir.
    • Yukarıdaki sabit sınır, bu tür işlemlerin iptal edilmesine neden olacaktır (Linux sanal bellek adres alanının aşırı yüklenmesine izin verdiğinden, aksi takdirde iyi çalışmış olsalar bile).

Daha Yeni CGruplar

Daha fazla kontrol sunar, ancak şu anda kullanımı daha karmaşıktır:

  • Ulimit teklifini geliştirir.
    • memory.max_usage_in_bytes fiziksel belleği ayrı ayrı hesaplayabilir ve sınırlayabilir.
    • Halbuki ulimit -mve / veya rssin limits.confbenzer işlevler sunması amaçlanmıştır, ancak çekirdek Linux 2.4.30'dan beri işe yaramıyor!
  • İhtiyaç açılış, bazı çekirdek CGroup bayrakları etkinleştirmek için: cgroup_enable=memory swapaccount=1.
    • Bu, Ubuntu 16.04 ile varsayılan olarak gerçekleşmedi.
    • Muhtemelen ekstra muhasebe ek yükünün bazı performans etkileri nedeniyle.
  • cgroup / systemd şeyler nispeten yenidir ve adil bir şekilde değişmektedir, bu yüzden akış yukarı akı Linux dağıtım sağlayıcılarının henüz kullanımı kolay hale getirmediğini ima etmektedir. 14.04LTS ve 16.04LTS arasında, cgroups kullanmak için kullanıcı alanı araçları değişti.
    • cgm artık resmi olarak desteklenen kullanıcı alanı aracı gibi görünüyor.
    • systemd birim dosyalarının ssh gibi önemli hizmetlere öncelik tanımak için önceden tanımlanmış "satıcı / dağıtım" varsayılanları henüz görünmüyor.

Mevcut ayarları kontrol etmek için:

$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...

Örneğin, tek bir işlemin belleğini sınırlamak için:

$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed

RAM'i bir arka plan işlemi olarak çiğnediğini ve sonra öldürüldüğünü görmek için:

$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
 0.0  0.0  2876
 102  0.2 44056
 103  0.5 85024
 103  1.0 166944
 ...
98.9  5.6 920552
99.1  4.3 718196
[1]+  Killed                  bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'

Bellek isteklerinde üstel (2 gücü) büyümeye dikkat edin.

Gelecekte, SSH ve grafik yığını gibi önemli şeyler için "dağıtım / satıcılar" ın grup önceliklerini ve sınırlarını (systemd birimleri aracılığıyla) önceden yapılandırmayı görmeyi umuyoruz, böylece asla hafızadan aç kalmayacaklar.


2

Programı askıya almak için Ctrl- tuşuna basabilirsiniz z. Ardından kill %1(veya iş numarası ne olursa olsun veya PID'yi kullanabilirsiniz) yapabilirsiniz.

Bir işlem için kullanılabilir ulimitbellek miktarını sınırlamaya çalışmak için komutu kullanabilirsiniz .


Ctrl-Z güzel, ama genellikle bir Matlab GUI çalıştırıyorum ve kontrol terminalinin izini kaybettim, bu yüzden Ctrl-Z tuşunu basmanın kolay bir yolu yok. GUI, uygulama ne olursa olsun SIGSTOP göndermek için bir kısayol tuşu olsaydı iyi olurdu!
nibot

kill -STOP <pid>Ctrl-Z ile aynı şeyi yapacak olan koşabilirsiniz .
hlovdal

Evet, ancak tüm sorun, böyle bir durumda, sistemin o kadar duyarlı olmamasıdır ki, bir komut istemine ulaşmak uzun zaman alır (ya da sonsuza dek).
nibot

1

Kaynak kullanımını sınırlamak ve bu tür sorunları önlemek için CGroup'ları kullanabilirsiniz: https://en.wikipedia.org/wiki/Cgroups


Lütfen yanıtınıza gerekli bilgileri ekleyin ve bağlantıyı yalnızca ilişkilendirme ve daha fazla okuma için kullanın. Bu bağlantı, CGroups'un ne olduğunu açıklar, ancak bağlantıdan sorunu çözmek için nasıl kullanılacağı açık değildir. Sorunun çözümünü açıklamak için cevabınızı genişletebilir misiniz? Teşekkürler.
fixer1234

0

GUI, uygulama ne olursa olsun SIGSTOP göndermek için bir kısayol tuşu olsaydı iyi olurdu!

Her zaman klasik xkillkomut vardır (sistemimdeki xorg-x11-apps-7.4-14.fc14.src.rpm'den). Sanırım hedef pencereyi öldürmek yerine SIGSTOP gönderen bir klon yapmak çok zor olmamalı.


Bazı tuş kombinasyonlarına basarak xkill'in nasıl hızlı bir şekilde başlamasını sağlayabilirim?
nibot

Emin değilim. Hem gnome hem de KDE'nin programları başlatmak için kullanılabilecek bazı küresel kısayol işlevlerine sahip olduğunu varsayıyorum.
hlovdal
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.