Naprej Nazaj Kazalo

8. Kako preprečimo, da bi procesi drug drugemu hodili v zelje?

Razporejevalnik opravil skrbi za časovno ločitev procesov, torej za to, da si naenkrat lasti procesor le en proces. Poleg tega moramo procese ločiti tudi prostorsko, tako da procesi uporabljajo le kos pomnilnika, ki jim je dodeljen, ne pa tudi prostora, dodeljenega drugim procesom. Celo če predpostavimo, da bi programi poskušali biti kooperativni, ne moremo dopustiti, da bi napaka v enem od njih poškodovala druge. Naloge operacijskega sistema v zvezi z dodeljevanjem prostora so znane pod imenom upravljanje pomnilnika (angl. memory management).

Vsak proces v zverinjaku potrebuje svoj kos pomnilnika, torej prostor, v katerem bo izvajal svojo kodo ter hranil spremenljivke in rezultate. Lahko si zamislimo, da del tega prostora zaseda programski segment, ki hrani programske ukaze v strojnem jeziku in iz katerega lahko samo beremo, ter podatkovni segment, ki vsebuje vse spremenljivke, uporabljene v programu, in v katerega je mogoče tudi pisati. Podatkovni segment se res razlikuje od enega procesa do drugega; programski pa ne nujno: če dva procesa poganjata isto programsko kodo, Unix varčuje s prostorom in samodejno poskrbi, da je programski segment naložen v pomnilnik samo enkrat.

8.1 Virtualni pomnilnik: preprosta razlaga

Učinkovitost ravnanja s prostorom je pomembna, saj je pomnilnik drag. Včasih ga nimamo dovolj, da bi naenkrat držali v pomnilniku vse programe, ki se izvajajo, še posebej, če je med njimi kak velik program, denimo strežnik X. Unix težavo zaobide s tehniko, ki je znana kot virtualni pomnilnik. Jedro ne poskuša držati v pomnilniku celotne kode in podatkov za posamezni proces, ampak samo relativni manjši delovni nabor. Preostanek pomnilniške slike procesa je shranjen na posebnem prostoru na disku (tako imenovani izmenjalni prostor).

V preteklosti, ko so imeli računalniki malo pomnilnika, je ,,včasih`` iz prejšnjega odstavka pomenilo ,,skoraj vedno``. Dandanes pomnilnik ni več tako drag, kot je bil včasih, in celo računalniki s spodnjega konca lestvice ga premorejo kar precej. Na sodobnih enouporabniških računalnikih, ki imajo 64 ali več megabajtov pomnilnika, je mogoče poganjati okna X in običajno paleto opravil, ne da bi bilo treba uporabiti izmenjalni prostor.

8.2 Virtualni pomnilnik: podrobnosti

V prejšnjem razdelku smo stvari namenoma poenostavili. Drži, da programi obravnavajo pomnilnik kot dolgo vrsto pomnilniških naslovov, ki lahko presega fizični pomnilnik, in da to iluzijo vzdržujemo z diskovnim izmenjavanjem. Vendar pa premore običajni računalnik nič manj kot pet različnih vrst pomnilnika, in razlike med njimi so pomembne, kadar moramo iz računalnika iztisniti kar največ. Da bi resnično razumeli, kaj se dogaja v računalniku, moramo razumeti tudi, kako delujejo posamezne vrste pomnilnika.

Pet vrst pomnilnika je: procesorski registri, notranji predpomnilnik (na samem čipu), zunanji predpomnilnik (na ločenem čipu), glavni pomnilnik, ter disk. Razlog za toliko različnih vrst pomnilnika je en sam: hitrost se plača. Našteli smo jih od najhitrejšega do najpočasnejšega, oziroma od najdražjega do najcenejšega. Registri so najhitrejša in najdražja oblika pomnilnika, do njih pa lahko dostopamo približno milijardokrat na sekundo. Disk je najpočasnejša in najcenejša oblika; do podatkov na njem lahko dostopamo približno stokrat na sekundo.

Sledi seznam z vrednostmi za običajni namizni računalnik, kot so bile aktualne spomladi leta 2000. Hitrost in velikost bosta s časom naraščali, cene pa padale, vendar pa lahko pričakujete, da bodo razmerja med njimi ostala bolj ali manj enaka. In ta razmerja določajo pomnilniško hierarhijo.

Disk

Velikost 13.000 MB Hitrost: 100 KB/s

Pomnilnik

Velikost 256 MB Hitrost: 100 MB/s

Zunanji predpomnilnik

Velikost 512 KB Hitrost: 250 KB/s

Notranji predpomnilnik

Velikost 32 KB Hitrost: 500 KB/s

Register

Velikost 28 B Hitrost: 1000 KB/s

Celotnega računalnika ne moremo zgraditi iz najhitrejše vrste pomnilnika. Dosti predrago bi bilo -- in celo če to ne bi bilo res, hitri pomnilnik ni trajen. Brž ko izključimo napajanje, izgubi svojo vrednost. Zato morajo računalniki imeti tudi neko vrsto trajnega pomnilnika -- npr. disk -- ki ohrani svojo vrednost tudi, ko izklopimo napajanje. Med hitrostjo procesorjev in hitrostjo diskov pa zeva ogromna vrzel. Srednje tri ravni v hierarhiji procesorjev -- notranji predpomnilnik, zunanji predpomnilnik in glavni pomnilnik -- obstajajo zgolj, da premostijo to vrzel.

Linux in drugi Unixi uporabljajo virtualni pomnilnik. To pomeni, da se operacijski sistem vede, kot da bi imel na razpolago dosti več pomnilnika, kot pa ga je dejansko na voljo. Fizični pomnilnik se obnaša kot vrsta ,,oken`` na mnogo večjem ,,virtualnem`` pomnilniku, katerega večina je v katerem koli trenutku shranjena na disku, na posebnem prostoru, imenovanem izmenjalni prostor. Ne da bi se uporabniški procesi tega zavedali, operacijski sistem sproti prenaša bloke podatkov (takemu bloku pravimo tudi page, slov. stran) iz pomnilnika na disk in nazaj, in tako ustvarja iluzijo velikega pomnilnika. Končni rezultat je, da je tak virtualni pomnilnik dosti večji, pa niti ne dosti počasnejši od fizičnega.

Koliko počasnejši je virtualni pomnilnik od fizičnega je odvisno od tega kako dobro algoritmi za izmenjevanje v operacijskem sistemu predvidijo porabo pomnilnika. Na srečo večina sklicev na pomnilniške lokacije, ki si sledijo v kratkem času, bere oziroma piše v pomnilniške lokacije, ki so tudi prostorsko blizu skupaj. Ta lepa lastnost je znana kot lokalnost, oziroma lokalnost sklicevanja. Če bi, nasprotno, bili pomnilniški sklici naključno raztreseni po celotnem pomnilniškem prostoru, bi morali ob vsakem sklicu na pomnilniško lokacijo prebrati podatke z diska, in virtualni pomnilnik bi bil enako počasen kot disk. Ker pa programi kažejo lokalnost, lahko operacijski sistem opravi pomnilniška sklicevanja z razmeroma malo branja z diska.

Izkustveno je bilo ugotovljeno, da je najučinkovitejša metoda za široko paleto vzorcev rabe pomnilnika nadvse preprosta: algoritem se imenuje LRU (angl. Least Recently Used, ,,tisti, ki najdlje ni bil rabljen``). Mehanizem za virtualni pomnilnik naloži diskovni blok v svoj delovni nabor, ko se za to pokaže potreba. Če fizičnega pomnilnika ni več na voljo, iz njega zbriše blok, ki najdlje ni bil rabljen. Vse različice Unixa, kot tudi večina drugih operacijskih sistemov, ki uporabljajo virtualni pomnilnik, uporablja to ali ono različico algoritma LRU.

Virtualni pomnilnik je prvi člen v premostitvi vrzeli v hitrostih diska in procesorja, in ga izrecno upravlja operacijski sistem. Podobna, čeprav nekaj manjša vrzel zeva tudi med hitrostjo glavnega pomnilnika in hitrostjo procesorja. Notranji in zunanji predpomnilnik rešujeta ta problem s tehniko, ki je podobna pravkar opisani.

Tako kot se fizični glavni pomnilnik obnaša kot vrsta oken v izmenjalnem prostoru na disku, se tudi zunanji predpomnilnik obnaša kot okna v glavnem pomnilniku. Zunanji predpomnilnik je hitrejši od glavnega (250 milijonov dostopov na sekundo proti 100 milijonom), a manjši. Računalnik - natančneje, upravljalnik pomnilnika - izvaja v njem algoritem LRU na blokih podatkov iz glavnega pomnilnika. Iz zgodovinskih razlogov se tu pomnilniška enota imenuje ,,vrstica`` (angl. line) namesto ,,stran`` (angl. page).

Nismo še končali. Še zadnji korak v pospešitvi je notranji predpomnilnik. Ta izvaja algoritem LRU na blokih podatkov iz zunanjega pomnilnika. Je še hitrejši in še manjši - tako majhen pravzaprav, da je kar del mikroprocesorskega čipa.

Če bi radi napisali čim hitrejše programe, je dobro, da vemo te podrobnosti. Programi tečejo tem hitreje, čim večjo lokalnost imajo, saj je tedaj algoritem LRU bolj učinkovit. Najenostavnejši način, da dosežemo, da so programi hitri, je, da so majhni. Če programa ne zavira kopica branj in pisanj z diska ali omrežja, bo navadno tekel s hitrostjo najmanjšega predpomnilnika, v katerega ga lahko shranimo.

Če ne moremo napraviti celotnega programa tako majhnega, se včasih splača potruditi in časovno kritične dele napisati tako, da so čim bolj lokalni. Podrobnosti tehnik za takšna fina uglaševanja presegajo ta navodila; do takrat, ko jih boste potrebovali, boste verjetno že dovolj domači s prevajalnikom, da boste mnoge od njih odkrili sami.

8.3 Enota za upravljanje pomnilnika

Celo če imamo na voljo dovolj fizičnega pomnilnika, da diskovno izmenjevanje ni potrebno, ima del operacijskega sistema, zadolžen za upravljanje pomnilnika, še vedno pomembno nalogo. Paziti mora na to, da lahko vsak program spreminja le svoj podatkovni segment -- preprečiti mora torej, da bi okvarjen ali zlonameren program poškodoval podatke, ki pripadajo drugemu programu. Zato vodi knjigovodstvo o uporabljenih podatkovnih in programskih segmentih. Vsakič, ko program zahteva dodatni pomnilnik, ali pa ko sprosti pomnilnik (slednje se navadno zgodi, ko program zaključi z delom), mora ažurirati tabelo.

Tabela se uporablja za posredovanje ukazov specializiranemu kosu strojne opreme, imenovanem MMU (angl. memory management unit, enota za upravljanje pomnilnika). Sodobni mikroprocesorji imajo enoto MMU že integrirano na sam procesorski čip. Enota MMU ima možnost, da ,,ogradi`` posamezna območja pomnilnika, tako da so poskusi poseganja izven tega območja zavrnjeni in izzovejo posebno vrsto prekinitve.

Če ste v Unixu že kdaj naleteli na napako ,,Segmentation fault, core dumped`` ali kaj podobnega -- to je to. Proces je poskusil poseči po delu pomnilnika izven svojega podatkovnega segmenta, kar mu je operacijski sistem preprečil in ga prisilno zaključil. Takšno obnašanje je posledica napake v programu -- datoteka core s pomnilniško sliko procesa ob smrti, ki jo operacijski sistem ob tej priliki zapiše na disk, je diagnostična informacija, ki naj bi bila v pomoč programerju pri iskanju napake.

Poleg omejitve pomnilnika obstaja še en vidik varovanja procesov pred drugimi procesi. Nadzor želimo imeti tudi nad dostopom do datotek, tako da okvarjen ali zlonameren program ne more poškodovati katere od ključnih datotek na disku. Zato pozna Unix dovolilnice za datoteke, o katerih bomo več povedali pozneje.


Naprej Nazaj Kazalo