Bilgisayarım süreçlerin birbiri üzerine çıkmasına nasıl engel olur?

Çekirdek planlayıcısı, süreçlerin bir zamanda dilimine bölünmesi işine bakar. işletim sisteminiz de ayrıca bu süreçleri bir alana bölmek zorundadır, böylece süreçler birbirlerinin üzerine çıkamazlar; çalıştığı bellek. Tüm programların işbirliği içinde olmaya çalıştığını varsaysanız bile, içlerinden birinde, diğerlerin işini bozabilecek bir hatanın olmasını istemezsiniz. İşletim sisteminizin bu problemi çözmek için yaptığı işe bellek yönetimi denir.

Hayvanat bahçenizdeki her süreç, kodu çalıştıracağı ve değişkenleri ve sonuçları içinde tutacağı kendi bellek alanına ihtiyaç duyar. Bu takımın salt okunur bir kod parçasından (code segment) (süreç komutlarını içeren) ve yazılabilir veri parçalasından (data segment) (tüm süreçlerin değişken belleğini içeren) oluştuğunu düşünebilirsiniz. Veri parçası her süreç için gerçekten tektir. Ancak aynı kodu iki süreç çalıştırırsa, Unix verimlilik açısından otomatik olarak bu süreçleri yalnız bir kod parçasını paylaşacak şekilde düzenler.

Sanal bellek: basit sürüm

Verimlilik önemlidir, çünkü bellek pahalıdır. Kimi zaman makinenin çalıştırdığı tüm programların bütünlüğünü koruyacak kadar belleğe sahip değilsinizdir. Özellikle X sunucusu gibi büyük bir programı kullanıyorsanız. Bundan kaçınmak için Unix, sanal bellek denilen bir tekniği kullanır. Sanal bellek, bellekteki bir süreç için kodun ve verinin tamamını tutmaya çalışmaz. Onun yerine, yalnızca nispeten daha kısa bir çalışma takımını bulundurur; sürecin geri kalan bütün durumları sabit diskinizde takas alanı denilen özel bir yerde bırakılır.

Dikkat edin, bir önceki paragraftaki "kimi zaman", "hemen hemen her zaman" anlamında. Genellikle belleğin boyutu, çalışan programlarının boyutuna bağlı olarak küçüktü. Bu yüzden takaslama yaygındı. Bugünlerde bellek daha az pahalıdır ve alt uç makineler bile pek çoğuna sahiptir. 64 MB ve üstü modern tek kullanıclı makineler üzerinde, X'in ve tipik iş gruplarının çekirdeğe yüklenmesinden sonra takaslama olmaksızın çalıştırılmaları mümkümküdür.

Sanal bellek: detaylı sürüm

Aslında, son kısım bazı şeyleri bir miktar basitleştirmiştir. Evet, programlar belleğinizin çoğunu fiziksel bellekten daha çok olan, büyük, yassı adres bankası olarak görür ve takaslama bu yanılsamayı giderir. Ancak donanımınız aslında, içerisinde beş farklı tür bellekten daha azını bulundurmaz ve programların maksimum hız için ayarlanması zorunluluğu olduğu zaman aralarındaki farklılıklar iyi bir anlaşma konusu olabilir. Gerçekten de makinenizde neler olup bittiğini anlamak için, tüm bunların nasıl çalıştıklarını anlamalısınız.

Beş bellek türü şunlardır : işlemci yazmaçları, dahili (veya çip üstü) önbellek, harici (veya çip dışı) önbellek, ana bellek ve disk. Çok tür olmasının nedeni ise basittir: hız para demektir. Bellek türlerini erişim zamanına göre artan, maliyete göre ise azalan sırada listeledim. Disk en yavaş, en ucuz ve saniyede 100 rastgele erişim yapabiliyor iken, yazmaç belleği en hızlı, en pahalı ve saniyede milyarlarca kez rastgele erişilebilir bir bellektir.

Burada, tipik bir masaüstü makinesi için ilk 2000 hızı yansıtan bir listenin tamamı vardır. Hız ve kapasite artıp, fiyatlar düşüyor iken, bu oranların adil bir şekilde sabit olarak kalacağını ve o oranların bellek hiyerarşisini biçimlendirdiğini düşünebilirsiniz.

Disk Size: 13000MB Accesses: 100KB/sec

Ana Bellek Size: 256MB Accesses: 100M/sec

Harici Önbellek Size: 512KB Accesses: 250M/sec

Dahili Cache Size: 32KB Accesses: 500M/sec

İşlemci Size: 28 bytes Accesses: 1000M/sec

Herşey, en hızlı tür bellekler üzerine inşa edilemez. Bu yol çok maliyetli olabilir ve eğer öyle olmasa bile, hızlı bellek geçicidir. Güç kesildiği zaman üzerindeki verileri kaybedecektir. Böylece, bilgisayarların sabit diske veya güç kesildiği zaman verileri tutabilen geçici olmayan türdeki depolama cihazlarına sahip olması şarttır. İşlemciler ile disklerin hızları arasında devasa bir uyumsuzluk vardır. Bellek hiyerarşisinin üç orta seviyesi (dahili önbellek, harici önbellek ve ana bellek), temelde bu uçurumda bir köprü görevi görmek için vardır.

Linux ve diğer Unixler sanal bellek denilen bir özelliğe sahiptir. Bu demek oluyor ki işletim sistemi sahip olduğundan daha fazla ana bellek varmış gibi davranır. Gerçek fiziksel ana belleğiniz, gerçekte herhangi bir zaman diliminde takas alanı denilen diskteki özel bir bölümde, çok daha büyük bir sanal bellek alanı üzerindeki pencere ya da önbellek takımı gibi davranır. Kullanıcı programlarının görüşlerinin dışında, işletim sistemi bu ilüzyonu sürdürebilmek için bellek ve disk arasında veri bloklarını ("pages") taşır. Sonuç olarak, sanal belleğiniz gerçek bellekten çok daha büyüktür, ancak çok fazla yavaş değildir.

Sanal belleğinizin fiziksel bellekten ne kadar yavaş olduğu, işletim sisteminin takaslama algoritmalarının, programlarınızın sanal belleği kullanan yolu ile ne kadar uyumlu olduğuna bağlıdır. Neyse ki birbirine yakın zamanlarda olan bellek okuma ve yazmaları kümelenme eğilimindedirler. Bu eğilim yerellik (locality) veya daha resmi şekliyle referans yerelliği (locality of reference) olarak adlandırılır ve bu iyi birşeydir. Eğer bellek kaynakları rastgele sanal uzaydan geçerse; bir disk kadar yavaş olabilecek her yeni kaynak ve sanal bellek için diskten okuma veya yazma yapmalısınız. Ancak programların aslında sağlam bir yerellik sergilemesinden dolayı, işletim sisteminiz referans başına nispeten az takasmalama yapabilmektedir.

Tecrübelere dayanılarak, bellek kullanım modellerinin geniş bir sınıfı için en etkili metodun oldukça basit olduğu saptanmıştır. Bu metot, LRU veya "least recently used - en yakın zamanda en az kullanılan" algotiması olarak adlandırılır. Sanal bellek sistemi ihtiyaç duyduğu için, disk bloklarını kendi "çalışma kümelerine (working set)" geçirir. Çalışma kümesi için fiziksel belleği tükettiğinde, en yakın zamanda kullanılmış bloğu atar. Tüm Unixler ve diğer pekçok sanal bellek işletim sistemi, LRU'da küçük varyasyonlar kullanır.

Sanal bellek disk ve işlemci hızları arasındaki köprünün ilk bağlantısıdır. Açıkça işletim sistemi tarafından yönetilir. Ancak fiziksel ana belleğin hızı ve bir işlemcinin yazmaç belleklerine erişebileceği hızları arasında hala önemli bir uçurum vardır. Harici ve dahili önbellek, bu duruma bahsettiğim gibi sanal belleğe benzer bir teknik kullanarak adresler.

Nitekim fiziksel ana belleğin, disk takas alanı üzerindeki pencere veya önbellek kümesi olarak davrandığı gibi, harici önbellek de ana bellekte pencereler gibi hareket eder. Harici önbellek daha hızlı (100 M'den ziyade, saniyede 250M erişim) ve daha küçüktür. Donanım (özellikle, bilgisayarınızın bellek denetleyicisi) LRU işini, harici önbellekteki ana bellekten getirilmiş veri blokları üzerinde yapar. Tarihsel nedenlerden dolayı önbellek takaslama ünitesi bir sayfadan ziyade, hat olarak adlandırılır.

Ancak henuz bitirmedik. Dahili önbellek, harici önbellek kısımlarını önbellekleyerek, etkin hızdaki en son noktayı bize verir. Şimdi daha hızlı ve küçüktür - aslında işlemci çipinin hemen altında yer alır.

Eğer gerçekten programlarınızı hızlandırmak istiyorsanız, bu detayları bilmek faydalı olacaktır. Sağlam bir yerellik olduğu zaman programlarınız daha hızlı çalışır, çünkü bu iş önbellekleme işini daha iyi yapar. Bu nedenle programları hızlı bir hale getirmenin en kolay yolu onları küçültmektir. Eğer bir program birçok giriş/çıkış veya ağ olaylarındaki beklemeler tarafından yavaşlatılmamışsa, genellikle uygun olacağı en küçük önbellek hızında çalışacaktır.

Eğer programınızı bir bütün olarak küçültemiyorsanız, kritik hızdaki parçaları ayarlamak biraz çaba gerektirecektir. Böylelikle faydalı olabilecek daha sağlam bir yerelliğe sahip olacaklardır. Bu tarzdaki ayarlama tekniklerinin detayları, bu bilgilendirici rehberin de ötesinde bir alandadır. Bunlara ihtiyaç duyacağınız zamana kadar, pekçoğunu kendi kendinize çözebilecek kadar, epey bir derleyiciyle içli dışlı olacaksınız.

Bellek Yönetim Ünitesi

Takaslamadan sakınacak kadar fiziksel çekirdeğiniz olduğu zaman bile, bellek yöneticisi adında işletim sisteminizin bir parçasının hala yapacağı önemli bir işi vardır. Bellek yöneticisi, programların yalnızca kendi veri parçalarını değiştirebileceklerinden emin olmalıdır. Yani, bir program içindeki hatalı veya kötü niyetli kodların bir başka programın verisini ayıklamasını engeller. Bunu yapmak için, veri ve kod parçasının bir tablosunu tutar. Bir süreç ya da daha fazla bellek isteğinde bulunduğunda ya da belleği serbest bıraktığında (ikincisi genellikle sürecin çıkışında olur) tablo güncellenir.

Bu tablo, komutların donanımın temelinde bulunan, MMU veya bellek yönetim ünitesi diye adlandırılan özelleştirilmiş parçasına geçirilmesinde kullanılır. Modern işlemci çipleri, hemen altında inşa edilmiş MMU'lara sahiptir. MMU'nun bellek alanları etrafına set çekmek gibi bir yeteneği vardır. Böylelikle dışarıdaki bir başvuru reddedilecek ve özel bir kesme sinyalinin çıkarılmasına neden olacaktır.

Eğer hiç "Parçalama Hatası(Segmentation Fault)", "Çekirdek Boşaltıldı(Core Dumped)" veya benzer bir Unix mesajı gördüyseniz, tam olarak olan şudur; kendi parçası dışındaki belleğe(çekirdeğe) erişmeye çalışan bir program tarafından bulunulan bir girişim, ölümcül bir kesme çıkarır. Bu, program kodunda bir hata olduğunu gösterir; çekirdeğin boşalmasının arkasında, programcıya iz sürmede yardımcı olacak şekilde planlanmış tanısal bilgi yatar.

Bir diğer yaklaşım; süreçlerin, eriştikleri belleği ayırmasının yanında, birbirlerinden korumasıdır. Onların eriştikleri dosyaları kontrol edebiliyor olmak da istersiniz. Böylece hatalı ya da kötü niyetli bir program, sistemin önemli parçalarını bozamaz. Bu nedenle Unix'te, daha sonra bahsedeceğimiz dosya izinleri vardır.