Bir işlem için kullanılabilir bellek miktarını nasıl sınırlayabilirim?


11

Devam eden bir program geliştiriyorum; zaman zaman çok büyük miktarda bellek tahsis eder (8G fiziksel belleğe sahip bir makinede >> 10G), sistemin yanıt vermemesine neden olur. Sürecin ayırabileceği bellek miktarını sınırlamak istiyorum. Bunu yapmanın olağan yolu:

ulimit -m 4000000 ; ./myprogram

... 4GB'tan fazla bellek kullanmaya çalışırsa programımı öldürmelidir.

OS X El Capitan'da bunun bir etkisi yok gibi görünüyor; Hatta ulimit -m 1(hafızanın sadece 1KB için tüm programları sınırlayıcı!) etkisizdir.

Belirli bir işlem için kullanılabilir bellekte üst sınırı nasıl ayarlayabilirim?


Bunu her zamanki gibi yapmam derken ne demek istiyorsun? Daha spesifik olarak, bunu genellikle ne zaman yaparsınız? Ve bunu yaptığınızda, Mac OS X El Capitan'da mı yoksa başka bir ortamda mı kastediyorsunuz? Başarıyla ne zaman kullandığınıza bir örnek verebilir misiniz? Temel olarak, bu işlemin sizin için normalde işe yarayıp yaramadığını açıklığa kavuşturmaya çalışıyorum, ancak bu belirli program için çalışmıyor mu? Yoksa sizin için hiç işe yaramıyor, ama öyle mi düşünüyorsunuz?
Monomeeth

1
"Bunu her zamanki gibi yaparım" derken, bunu unix'in diğer lezzetleri üzerinde yapacağım yolu kastediyorum. Sadece ulimit -mLinux üzerinde çalışmadığını (> 2.4.30) keşfettim , ancak ulimit -vyine de beklendiği gibi çalışıyor. (Gibi ulimit -m, ulimit -vOS X üzerinde de bir etkisi yok gibi görünüyor.)
cpcallen

Bu, yazdığınız programda bir bellek sızıntısı olduğu ve daha iyi çöp toplama işlemi yapmanız gerektiği anlaşılıyor. Hareket halindeyken bellek yönetimini okudunuz mu?
Todd Dabney

1
Hayır, bir bellek sızıntısı değil, yalnızca çok büyük bir potansiyel durum uzayının grafik araması. Çeşitli iç yapılar çok büyük olursa aramayı iptal etmek için kod ekleyebilirim, ancak aynı şeyi yapmayı bekliyordum (makinenin büyük girdilerle sıkışmasını önleyebildim).
cpcallen

Yanıtlar:


1

Bellek kullanımınızı sınırlamak için iki yaklaşım vardır: Ex facto ve preemptive. Yani, programınız çok büyüdükten sonra öldürmeye çalışabilirsiniz ya da ilk etapta çok büyük olmamak için programlayabilirsiniz.

Eski post facto yaklaşımında ısrar ediyorsanız, aşağıdaki Bash betiğini kullanabilirsiniz. Bu komut dosyası ilk olarak processid pid ile işlemin kullandığı bellek miktarını bulur ("yerleşik küme boyutu" ile tanımlandığı gibi), grep kullanarak sayısal olmayan tüm verileri filtreler ve miktarı n değişkeni olarak kaydeder. Komut dosyası n'nin belirttiğiniz x değerinden büyük olup olmadığını denetler. Eğer öyleyse, processid pid ile süreç öldürülür.

Lütfen aklınızda bulundurun:

  1. <pid>Programınızın işlem kimliğiyle değiştirmelisiniz .
  2. Sen değiştirmeniz gerekir <x>program aşmak istemiyorum rss = "yerleşik seti boyutu" (yani gerçek bellek boyutu) ile.

n=$(ps -<pid> -o rss | grep '[0-9]') if [ $n -gt <x> ]; then kill -9 <pid>; fi

Bunun her y saniyede bir çalışmasını istiyorsanız, sadece bir döngüye koyun ve her yinelemeden sonra y saniye beklemesini söyleyin. Bunu kullanarak da benzer bir komut yazabilirsiniz top. Başlangıç ​​noktanız olurdu top -l 1|grep "<pid>"|awk '{print $10}'.

@ kenorb'un yanıtı senaryomda bana yardımcı oldu


Soruyu cevapladığına inanırken uzun vadede manuel bellek tahsisini kullanarak önleyici bir yaklaşım benimsemenin daha iyi bir programlama tasarımı olduğuna inanıyorum.

Öncelikle, bellek kullanımının gerçekten bir sorun olduğundan emin misiniz? Go belgeleri şunları belirtir:

Go bellek ayırıcısı, geniş bir sanal bellek bölgesini ayırma alanı olarak ayırır. Bu sanal bellek, belirli Git işlemi için yereldir; rezervasyon diğer bellek işlemlerini mahrum bırakmaz.

Hâlâ bir sorununuz olduğunu düşünüyorsanız, belleğinizi C programlama dilinde yapıldığı gibi manuel olarak yönetmenizi öneririm. Go C yazıldığından, C bellek yönetimine / tahsisatına girmenin yolları olabileceğinden şüphelendim ve gerçekten de var. Bu github deposuna bakın ,

sisteminiz için standart C ayırıcı üzerinden manuel bellek yönetimi yapmanızı sağlar. Malloc, calloc ve içermeyen ince bir sargıdır. Sisteminiz için bu işlevlerle ilgili ayrıntılar için man malloc'a bakın. Bu kütüphane cgo kullanıyor.

Kullanım durumu şu şekilde verilir:

Bunu neden istiyorsun?

Bir program bellek basıncına neden oluyorsa veya sistem belleği yetersiz kalıyorsa, bellek ayırmalarını ve yeniden konumlandırmaları el ile kontrol etmek yararlı olabilir. Go, tahsisleri kontrol etmenize yardımcı olabilir, ancak gereksiz verileri açıkça yeniden konumlandırmak mümkün değildir.

Bu daha iyi uzun vadeli bir çözüm gibi görünüyor.

C (bellek yönetimi dahil) hakkında daha fazla bilgi edinmek istiyorsanız, C Programlama dili standart referanstır.


Bellek kullanımının gerçekten bir sorun olduğundan eminim. Program beklenmedik bir şekilde> 2x fiziksel bellek boyutuna ulaştığında, makine sayfa atma nedeniyle neredeyse tamamen yanıt vermedi. ^ C tuşuna bastığımda ve macOS'un fare tıklamalarına yanıt vermeye devam etmesi arasında yaklaşık bir saat sürdü; Bu arada dondurulmadığına dair tek kanıt, sabit sürücünün hızla gürültüye maruz kalmasıydı.
cpcallen

Bu muhtemelen pratikte makul bir çözümdür, ancak (Darwin dışı) UNIX İşletim Sistemlerindeki ulimitin aksine, kill komutunu başarıyla yürütmek için zamanında yeterli bellek ayırabilmeye bağlıdır. Çekirdek tarafından uygulanan işlem boyutu sınırlarını tercih ederim.
cpcallen

@cpcallen bazı aramalar yapıyor gibi görünüyor. Görünüşe göre OSX de bu değişikliği aldı. Adres alanını sınırlamak için -v seçeneğini deneyin
Evan Rosica

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.