Smalltalks virtuella maskin
Detta är ett utdrag ur rapporten Smalltalk - en översikt (Fröjdh, Jernevad, Andreen, Röhsman 2003). Texten är copyright Henrik Jernevad.
Följande avsnitt är baserade på informationen som finns i boken Smalltalk-80, The Language and Its Implementation (Goldberg och Robson 1983) skriven av några av Smalltalks skapare. Enligt den kan ett Smalltalk-system grovt sett delas upp i två delar: en virtuell bild (eng. “virtual image“) och en virtuell maskin (eng. “virtual machine“).
Virtuell bild, bytekod och virtuell maskin
Alla objekt programmeraren skriver i sin kod görs om av Smalltalks kompilator till så kallad bytekod (eng. “byte code“). Bytekoden består av åtta bitar långa koder som motsvarar grundläggande instruktioner för en dator, till exempel att skriva något till minnet. Fördelen med bytekod är att den är maskinoberoende, det vill säga koderna är inte knutna till en viss datormiljö utan till språket Smalltalk. Detta gör att samma bytekod kan köras på flera olika datorsystem. Detta är inte fallet för den maskinkod som genereras av många andra kompilatorer, till exempel för C++.
Denna bytekod lagras i något som kallas en virtuell bild. Det är en fil som innehåller alla objekt som hör till ett program. Bilden läses sedan in i Smalltalks virtuella maskin och görs där om till maskinkod anpassad till den hårdvara den körs på av en så kallad tolk (eng. “interpreter“). Tolken har till sin hjälp en stack, vilket är en datastruktur som tillåter lagring av flera värden, som den använder för lagring av objekt under arbetets gång.
Hur den kompilerade koden ser ut
För varje metod i den ursprungliga koden skapar kompilatorn ett CompiledMethod-objekt. Denna innehåller förutom metodens bytekod en “literal frame“. I denna lagras information som är knuten till metoden men som inte direkt kan översättas i bytekod. Det kan till exempel vara konstanter eller anrop till andra metoder.
Som ett exempel har vi här funktionen incrementIndex, vars uppgift är att öka variabeln Index med fyra och sedan skicka tillbaka värdet av Index till anroparen. Funktionen ser i Smalltalk ut som följer:
^ Index := Index + 4
Operatorn := tilldelar variabeln på vänster sida (Index) värdet av högerledet (Index + 4) och returoperatorn ^ skickar värdet av Index till den funktion som anropade incrementIndex. Denna funktion efter den passerat kompilatorn och blivit en CompiledMethod ser ut så här:
| Bytekod | Förklaring |
|---|---|
| 64 | Lägg variabeln på den första literal frame-positionen (Index) på stacken. |
| 33 | Lägg konstanten på den andra literal frame-positionen (4) på stacken. |
| 176 | Skicka ett binärt meddelande med operatorn + (till Index). |
| 129, 192 | Spara det första värdet från stacken i variabeln på den första literal frame positionen (Index). |
| 124 | Skicka tillbaka värdet överst på stacken som värde för meddelandet incrementIndex. |
Literal frame
Association: #Index
4
Här finns varje operation den virtuella maskinen skall utföra beskriven med bytekod. Den information som finns lagrad i avsnittet literal frame i detta fall är en referens till variabeln Index och konstanten 4, båda som ju används i funktionen incrementIndex.
Minneshantering och skräpsamling
Den ena delen av Smalltalks virtuella maskin är som nyss nämnts är tolken. Den andra stora delen är objektminnet (eng. “object memory“). Dess uppgift är att hålla alla objekt i minnet och se till att oanvända objekt rensas bort. Följande information är baserad på webbsidan The Very Basics of Garbage Collection (Padron-McCarthy 2002).
Skräpsamlaren
Alla objekt skapas enligt order från programmeraren med funktionsanropet new. Dock ligger ansvaret för att rensa bort objekt när de inte längre behövs på Smalltalks minneshantering. Detta för att göra programmerarens uppgift lite lättare. Mer exakt så är det den så kallade skräpsamlaren (eng. “garbage collector“) som tar på sig uppgiften att rensa i minnet.
Olika algoritmer för skräpsamling
Det finns två stycken enkla algoritmer för att hålla reda på vilka objekt som används och vilka som kan kastas bort. De är referensräkning (eng. “reference counting“) och “mark and sweep“.
Referensräkning fungerar enligt principen att varje objekt har en räknare där information sparas om hur många andra objekt som har en referens till det. Dess största nackdel är dock att den inte klarar av så kallade cykliska referenser. De uppstår när en grupp objekt som egentligen inte används längre har kvar referenser till varandra.
Med mark and sweep-algoritmen får varje objekt en liten flagga som markerar om det är använt eller inte. Processen börjar med att skräpsamlaren nollställer alla sådana flaggor. Sedan i mark-fasen börjar den följa alla referenser den hittar med utgångspunkt ifrån objekt den vet existerar och markera varje funnet objekt som använt. Efter detta följer sweep-fasen där alla icke-markerade objekt tas bort.
Dessa två algoritmer går även med fördel att kombinera. Under senare år har även mer sofistikerade algoritmer för skräpsamling uppstått, men de två nämnda ovan är de som användes för Smalltalk-80.