Innehåll

Virtuellt minne

Virtuellt minne
Virtuellt minne, om MMU:n
Virtuellt minne, om swap

 


03/01-01 | Janne Johansson | icepic@64bits.se


Virtuellt minne, fortsättning

Man kan alltså låta den virtuella page som har området $2000-3000 ligga på den fysiska addressen $123000, och nästa page som har området $3000-4000 ligga på fysiska addressen $34000 osv. MMU:n har en fin tabell att läsa av varje gång det behövs, så den blir inte förvirrad av att omvandlingen inte följer samma regler som programmet gör. På det sättet uppstår ingen minnesfragmentering, eftersom allt baseras på enheter med storleken 1 page, och man kan ta vilken ledig page som helst, närsomhelst. Det gör också att man oftast använder hela minnesutrymmet jämnare, så att det blir enklare att finna fel i dåliga minneskretsar.

Det som ytterligare förbättrar situationen är att man i den virtuella delen får alla 32 bitarna att leka med för varje enskilt program. (om man har en 32-bitars cpu, vill säga) Man kan placera ut programmen på vilka virtuella adresser som helst, eller låta minne som programmen allokerar efter att de har kört igång, ligga vart som helst inom de 4 Gig som man normalt sett når.

Det enda lilla problemet är att folk sällan har 4 Gig RAM, och det är där swap kommer in. All den vinst som jag redan beskrivit ovan är tillgängligt om man har virtuellt minne, utan att använda en swap. Det finns OS som avsiktligt kör med virtuellt minne utan att tillåta swap, t.ex realtidsoperativsystem som QNX, där man ställer tidsgarantier till programmen som man inte kan hålla om man har swap.

Men hur fungerar swap då?

Antag att jag har ett program som allokerar $1000 bytes och sen laddar in en liten fil där. OS:et kan då säga till mitt program att minnet det fick ligger på $123000. Fast på riktigt kommer det att ligga på addressen $456000 istället. Inga konstigheter. MMU:n trixar så det blir rätt.

Men sen är det en massa andra program i datorn som suger minne och gör slut på allt. OS:et inser att den måste låna från någon. Mitt program verkar inte ha rört sitt minne på lång tid så det "åker dit". Då tar OS:et den page vars fysiska address är $456000 (som mitt program tror ligger på $123000) och ger till nåt annat program efter att ha kopierat ut datat som låg där till swappen.

Min virtuella address ($123000) pekas då om till att inte längre peka på $456000, utan en fysisk address där inget ram finns. Den andra processen som stal minnet har sin egen virtuella pekare, t.ex $234000 som pekar mot den fysiska addressen $456000 och kan läsa och skriva dit hur mycket som helst.

Är det sedan så att mitt program vaknar upp och bestämmer sig för att faktiskt läsa från den virtuella addressen den fått av OS:et ($123000) så kommer det att bli en "fault" även där. Men, den här faultens address är registrerad i minneshanteraren och den vet att anledningen till att det blev en fault är att dess minne har åkt ut på disk, så den återtar en sida som antingen är ledig eller som stjäls på samma sätt som beskrivs ovan.

Denna fysiska sida (t.ex. $40000) får nu bli den plats dit mitt program ska läsa och skriva, så OS:et laddar in datat från swappen till addressen $40000 och sen pekar den om den virtuella addressen $123000 som mitt program fortfarande tror på, till att peka mot $40000, sen återstartas mitt program igen och mitt program kör på som om inget hade hänt, trots att massor av saker har hänt under huven. Hela tiden har mitt program trott att datat låg på den virtuella addressen $123000 och att datat alltid var inladdat i RAM:et.

Med virtuellt minne och swap kan man alltså låna minne av andra processer och program, man kan ha program som allokerar en massa minne "för mycket" som efter ett tag får sitt data utlagt på swappen och som sedan kanske aldrig återtar det. Då kommer det inte dra en massa minne från andra processer som bättre behöver det.

Det finns också andra situationer där denna metod är bra. Det finns vissa programspråk som har svåra eller helt obefintliga minneshanteringsrutiner (Fortran sägs vara ett sånt t.ex) som gör att programmen sällan eller aldrig kan i förväg veta hur mycket minne som kommer gå åt. Dessa program brukar allokera stora mängder minne, i vissa specialfall upp emot 2 Gig minne, just-in-case.

Sen använder de så mycket minne som behövs och låter resten vara orört. Hade man då inte virtuellt minne skulle körning av ett sånt program vara döden, men i och med att man kan låta fysiskt minne tas i bruk allteftersom det faktiskt används så kommer ett sådant program inte vara värre än ett motsvarande program skrivet i ett "bättre" språk. Man inser ju lätt att metoden att överallokera i förväg givetvis "uppfanns" efter virtuellt minne, ingen skulle ha gjort nåt så dumt om man inte redan innan visste att OS:et löser problemet åt en.

Sen finns det ännu fler tricks som OS:et kan ta till. Det som beskrevs ovan kallas oftast "paging", dvs att enstaka sidor kastas ut för att ge plats till andra. Swapping brukar det kallas när hela program (med data) åker ut, och är ju oftast en nödåtgärd, eftersom det kräver att man swappar in extremt mycket mer data för att ens kunna köra en rad av programmet igen efteråt.

Men även i sådana situationer finns det knep att ta till. Ett av dem är att helt sonika kasta ut programmet. Det låter som en dum ide, men den har sin charm. Om man kan få ett lås av filsystemet på binären till programmet, då kan man välja att kasta bort binären istället för att lägga ut programmet på swappen, i det fall när man verkligen måste ta till swapning istället för paging. Eftersom man kan hålla ett lås på filen ser man till att ingen raderar den, och eftersom koden i minnesskyddade OS inte fick vara självmodifierande vet vi ju att det vi laddade in från disk förut är samma som det vi laddar in senare. Så i trånga situationer kan man kasta ut hela programmet och bara page:a ut det data som programmet har samlat på sig under körningen.

Inte bara för OS:et

Finessen att bara ladda in de delar av ett program som verkligen körs är ju bra även för program som ska hantera stora filer, t.ex databaser. De har ju ofta stora filer som de bollar med, även om de inte är i alla delar av databasen samtidigt. Med hjälp av virtuellt minne kan man låta enskilda program göra likadant som OS:et gjorde med programladdning.

I normala fall måste man antingen ladda in filen i sin helhet vilket kostar minne, eller så får man allokera en eller flera lagom stora buffertar och sen ladda in del för del, vilket leder till att du får lägga ner tid och energi på att ta reda på vilken storlek på buffertarna som passar bäst.

Här kan virtuellt minne hjälpa dig, du som skriver ett program kan få en fil "virtuellt inlagd" i minnet, varpå du får tillbaka det minnesområde (angivet med virtuella adresser förstås) där filen påstås ligga, t.ex $10000- $20000. När programmet sen läser från respektive page i det området kommer OS:et att ladda in just bara den biten, och lämna resten orört. Man skulle i teorin kunna gå igenom en 2 Gig stor fil och bara förbruka 4k minne, om OS:et nu använde samma page om och om igen för att ladda in filen. Utan att programmet skrivs på det viset.

För databaser och liknande program är det guld, eftersom de ofta har filer som är enormt stora, men där databasprogrammet rör sig i olika delar av databsen vid olika tillfällen.

Den som läst min tidigare artikel om cpu:erna och antalet bitar minns kanske att jag fastnade för att räkna antalet bitar efter hur mycket minne de kunde adressera snarare än hur många bitar operationerna kunde hantera.

Det kommer sig av att funktionen som jag beskrev, där programmen kan få filen inladdad i omgångar, sida för sida kräver att det finns nog med utrymme i den virtuella addressrymden för att rymma filen. Så en 32-bitars cpu kommer alltså som mest kunna mappa in en ~4 Gig stor fil i minnet, sen måste man iallafall göra allt i delar. (Det går även bort en hel del utrymme för bussar, OS:et, delade bibliotek med mera, så mellan 2-3 Gig är oftast den praktiska gränsen)

Har man däremot en 64-bitars cpu så kommer man ha plats för 18 miljarders miljarder bytes, minus de megabyte som går åt för bussar och OS. Filer (och speciellt databaser) med storlekar över 2-3 Gig är inget exceptionellt idag, medans enskilda filer som är större än 18 miljoner Terabyte får åtminstone mig att häpna.


« Föregående Nästa sida »

 




03/01-01 | Janne Johansson | icepic@64bits.se

Diskutera denna artikeln i vårt forum!