Fork () Linux'taki tüm işlem yığınını hemen kopyalar mı?


30

Bir fork()sistem çağrısı bir alt işlemi çalışan işlemden klonlar. İki işlem, PID'leri dışında aynıdır.

Doğal olarak, eğer işlemler yazmak yerine sadece yığınlarından okuyorsa, yığının kopyalanması çok büyük bir hafıza kaybı olacaktır.

Tüm işlem yığını kopyalandı mı? Yalnızca yazma işlemi bir yığın kopyayı tetikleyecek şekilde optimize edilmiş mi?

Yanıtlar:


19

Tamamı bir fork()mmap'e kullanılarak uygulanır / yazma üzerine kopyalayın.

Bu sadece öbekleri değil aynı zamanda paylaşılan kütüphaneleri, yığınları, BSS alanlarını da etkiler.

Bu, tesadüfen, ortaya çıkan 2 işlem (ebeveyn ve çocuk) gerçekte bellek aralıklarına yazmaya başlayana kadar çatalın son derece hafif bir işlem olduğu anlamına gelir. Bu özellik çatal bombalarının ölümcüllüğüne önemli bir katkıda bulunur - çekirdeğin sayfa çoğaltması ve farklılaşmasıyla aşırı yüklenmeden önce çok fazla işlemle karşılaşıyorsunuz.

Modern bir işletim sisteminde çekirdeğin basılı kopya gerçekleştirdiği bir işlem örneği bulmak için zorlanacaksınız (aygıt sürücüleri istisnadır) - VM işlevini kullanmak çok daha kolay, çok daha kolay ve daha verimlidir.

Hatta execve()aslında "lütfen / ld.so / whatnot, ardından çalıştır 'komutunu kullanın" - ve VM, işlemin RAM ve yürütme işlemine gerçek yüklemesini gerçekleştirir. Yerel başlatılmamış değişkenler bir sıfır sayfadan - sıfırları içeren özel salt okunur kopyala-yazdır sayfasından mmapedlenir, yerel başlatılmış değişkenler ikili dosyadan tekrar mmaplanır (tekrar yazılır kopyala), vb.


Dikkate değer istisnalardan biri Java süreçleridir. Ara "çatal java hafızasına" ve büyük etkileyen konularda onlarca bulacaksınız sunucu JVM veya gömülü JVM bir çökmesini sefil küçük kabuk komutu yürütmeye çalışırken "bellek ayrılamadı" , bu konu sistemik olduğunu (bunlar sadece rastgele bağlantılar istisna Java ortamlarına). Bu SO cevabı , JVM'nin çöp toplayıcı ve JIT derleyicisinin, işlemleri hafızanın paylaşılmasını engellemekle suçluyor.
WhiteWinterWolf

24

Linux çekirdeği fork()çağrıldığında Üzerine Kopyala'yı uygular . Sistem çağrıldığında, üst ve çocuğun paylaştığı sayfalar salt okunur olarak işaretlenir.

Salt okunur sayfada bir yazma yapılırsa, bellek iki işlem arasında artık aynı olmadığından kopyalanır. Bu nedenle, yalnızca okuma işlemleri gerçekleştiriliyorsa, sayfalar hiç kopyalanmayacaktır.


1
+1 Teşekkürler! 1. Lütfen referans linkleri verebilir misiniz? 2. Yığın tamamen veya kısmen kopyalandı mı?
Adam Matan

4
2. - Sayfalarda :) Çekirdeğin "yığın" ın ne olduğu hakkında çok az bir anlayışı vardır - çekirdek için, libc ayırıcılarının istediği gibi kullandığı mmapped özel sayfaların bir kısmıdır.
qdot

Bu gerçekten bir çatal bomba mı? Bana öyle geliyor ki, şu anki işlemi yapmaktan ziyade, bu kod fork()çağrı sonrası bir sonraki komuttan ziyade baştan başlayan aynı programın örneklerini yaratacak .
sherrellbc

@ mmk FYI, "İlginç notunuz" undan çok şaşırdım ve bu yüzden (Linux 3.2.0'da) görmek için test ettim ve doğru görünmüyor. /proc/self/pagemapTestin amacı için fiziksel sayfa haritalamanın sanal adresini belirlemek için kullanılır . Beklediğim gibi, büyük çocuk ve yalnızca büyük çocuk paylaşılan sayfayı yazarsa, ebeveyn ve orijinal çocuk onu paylaşmaya devam eder. Sadece büyük çocuk özel bir kopya ile bitiyor.
Celada

@Celada. Hmm. Bunu bir yerlerde okudum ve bahsettiği çekirdek sürümünü hatırlamıyorum (muhtemelen daha eski bir sürüm?), Bu yüzden artık geçerli olmayabilir.
MMK

10

Linux, Yazma üzerine Kopyalama yapar. Gibi forkyeni bir süreç yaratır, tahsis sayfalar salt okunur olarak işaretlenir ve ebeveyn ve çocuk arasında paylaşılır. Bunlardan biri bir sayfayı değiştirmeye çalıştığında, sayfanın kopyalanması ve sayfa tablosunun uygun şekilde ayarlanması ile sonuçlanan bir sayfa hatası üretilir.

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.