**Muistinhallinta** (engl. *memory management*) on keskeinen osa käyttöjärjestelmän ja tietokoneohjelman toimintaa tietokoneen resurssien hallinnassa ja muistin käsittelyssä.

Muisti voidaan jakaa käyttöjärjestelmän ja käyttäjän sovelluksien kesken, sekä käyttäjäavaruus voidaan jakaa edelleen useiden prosessien käyttöön. Muistin jakaminen dynaamisesti on muistinhallinnan tehtävä.

Taustaa
-------

Esimerkki ulkoisesta fragmentaatiosta. Lohkot A, B ja C varataan, jonka jälkeen B vapautetaan.
Tyypillisesti ohjelma on suoritusvalmiina massamuistilla. Kun ohjelmaa suoritetaan se ladataan tietokoneen muistiin prosessiksi. Tietokoneen muisti voi alkaa osoitteesta nolla, mutta ohjelman ensimmäisen osoitteen ei tarvitse olla nolla. Jos tiedetään ennalta mihin osoitteeseen ohjelma ladataan se voi käyttää absoluuttisia osoitteita. Ohjelma voi olla uudelleensijoitettava, jolloin ohjelman muistiviittaukset saavat lopullisen arvonsa latauksen yhteydessä. Osoitteet voivat myös muuttua suorituksen aikana, jolloin käytetään apuna tähän tarkoitettu laitteistoa (muistinhallintayksikköä).

Tietokoneen suorittimen käyttämään osoitteeseen viitataan tyypillisesti loogisena osoitteena ja muistinhallintayksikön käyttämää osoitetta kutsutaan fyysiseksi osoitteeksi. Käännösaikainen ja ja latausaikainen osoitteiden *sidonta* (engl. *binding*) tuottavat identtisiä loogisia ja fyysisiä osoitteita, mutta suorituksen aikaisessa sidonnassa ne eroavat. Suorituksen aikaisessa sidonnassa tuotettua loogista osoittetta kutsutaan virtuaaliosoitteeksi. Muistinhallintayksikkö muuntaa virtuaaliset osoitteet fyysisiksi osoitteiksi ajonaikaisesti.

Ohjelmat voivat käyttää ajonaikaisia kirjastoja, jolloin osa ohjelman toiminnoista linkitetään ohjelmaan latausvaiheessa. Käyttöjärjestelmä voi jakaa kerran ladatun kirjaston sen käyttäjien välillä, mutta kirjastosta voi olla useita versioita käytössä samaan aikaan.

Moniohjelmoinnin myötä tietokoneen muisti on jaettu useiden prosessien kesken. Tyyppillisesti ohjelmoija ei voi tietää etukäteen mitä muita ohjelmia on samaan aikaan muistissa, sekä halutaan mahdollisuus vaihtaa suoritettavaa ohjelmaa muistista suorittimen käytön maksimoimiseksi. Ohjelma, joka siirretty levylle voi tarvita sijoittaa eri paikkaan muistissa kun se palautetaan suoritukseen. Ohjelman haarautumisen käsittely sisältää osoitteen seuraavaksi suoritettavalle käskylle ja suorittimen sekä käyttöjärjestelmän on ylläpidettävä ohjelman muistiviittauksille osoitteen muunnosta.

Prosessit on myös suojattava toisten ohjelmien tahattomilta tai tahallisilta yrityksiltä haitata ohjelman toimintaa. Lisäksi ohjelmat voivat laskea muistiviittaukset kuten sijainnin taulukossa ajonaikaisesti. Lisäksi jos useampi prosessi toimii yhdessä ja käsittelee samaa tietoa tuo voidaan haluta jakaa sitä käsittelevien prosessien kesken.

Useimmat nykyaikaiset järjestelmät käyttävät virtuaalimuistia, joka perustuu yhteen tai molempiin perustekniikoista, jotka ovat segmentointi ja sivutus. Myös muistin osiointia (engl. *partitioning*) on käytetty nyt vanhentuneissa järjestelmissä. Kiinteän ja dynaamisen osioinnin heikkouksien johdosta syntyi *kaverijärjestelmä* (engl. *buddy system*), jossa varattava lohko jaetaan pienempiin mikäli tilaa ei ole riittävästi vapaana. Segmentointi jakaa muistin vaihtuvan kokoisiin lohkoihin, jolloin ohjelman ohjelmakoodi, pino ja keko sijoitetaan eri segmentteihin.

Sivutuksessa muisti jaetaan kiinteän kokoisiin lohkoihin, joita kutsutaan sivuiksi. Kun on tarvetta käyttää enemmän muistia kuin tietokoneessa on fyysisesti voidaan osa muistisivuista *sivuttaa levylle*. Sivutus mahdollistaa sen, että prosessin käyttämän fyysisen muistiavaruuden ei tarvitse olla yhtenäinen (jatkuva).

*Katso myös: Virtuaalimuisti ja Sivutus*

Keko
----

Keko on dynaamisesti hallittava muistialue, josta ohjelma varaa tarvitsemansa tilan tiedon käsittelyyn. Toisin kuin ajonaikaisen pinon käsittelyssä ohjelmoija voi itse hallita keosta varatun alueen elinkaaren ja voi luoda siihen tietorakenteen, jonka ohjelmoija palauttaa kutsujalle. Lisäksi ohjelmoija voi hallita varatun muistin määrää tarkemmin kuin pinolle, joka voi olla pieni.

Dynaaminen muistinvaraus
------------------------

Dynaaminen muistinvaraus (engl. *Dynamic Memory Allocation*) on muistinvarausmenetelmä, jossa tietokoneohjelma suorittaa ajon aikana muuttujan tai muistilohkon varauksen tietokoneen muistista. Dynaamista muistinvarausta käytetään, kun tarvittavan muistin määrää ei tiedetä etukäteen ohjelmaa kirjoitettaessa. Esimerkki tällaisesta tilanteesta on esimerkiksi kuvankäsittelyohjelma: ohjelmoija ei voi tietää etukäteen, minkä kokoisia kuvatiedostoja käyttäjä haluaa avata ohjelmalla.

Dynaamista muistinvarausta käytettäessä ohjelma ei voi tietää etukäteen, minkä keskusmuistin kohdan käyttöjärjestelmä sille antaa. Tämän takia dynaamisesti varattuja muistialueita käytetään epäsuorasti, yleensä osoittimen avulla.

Dynaamisesti varattu muisti varataan keosta (engl. *heap*).
C-kielellä dynaaminen muistinvaraus toteutetaan `malloc(), calloc(), free()` ja `realloc()` -funktioilla. Ajonaikaisesta pinosta voi varata automaattisesti vapautettavaa muistia `alloca()`-funktiolla, mutta tämä voi aiheuttaa pinon ylivuotovirheen (engl. *stack overflow*) mikäli riittävästi muistia ei ole saatavilla.

Dynaaminen muistinvaraus voi johtaa ohjelmointivirheisiin, kuten muistivuotoihin. Lisäksi varatun muistin vapautus voi viedä ennustamattoman paljon aikaa. Riskin vuoksi dynaamista muistinvarausta vältetään luotettavuutta vaativissa tai reaaliaikajärjestelmissä.
Ilmailun laatustandardi DO-178B (Software Considerations in Airborne Systems and Equipment Certification) kieltää dynaamisen muistinvarauksen käytön turvallisuuskriittisessä ilmailujärjestelmissä.

Muistisuojaus
-------------

Muistisuojaus on muistinhallinnan ominaisuus, joka tarkoittaa laitteiston kykyä estää ohjelmaa käyttämästä toiselle ohjelmalle varattua muistialuetta paitsi tarkasti määritellyissä tilanteissa. Yritys käyttää muistia ilman pääsyoikeutta aiheuttaa keskeytyksen, jolloin käyttöjärjestelmä voi pysäyttää tai resetoida ongelman aiheuttajan. Suojauksen käsittelee mikropiiri, jota käyttöjärjestelmä ohjaa.
Avainpohjaista menetelmää voidaan käyttää vahvistamaan sivupohjaista suojausta.

Katso myös
----------

* Automaattinen roskienkeräys
* ASLR

Lähteet
-------

* Jaakkola, Matti: Muuttujien tilanvaraus (Arkistoitu – Internet Archive)

### Viitteet

1. ↑  William Stallings: *Operating System Internals and Design Principles*, s. 306. Seventh edition. Prentice Hall, 2012. ISBN 978-0-13-230998-1. (englanniksi)
2. 1 2 3 4  Silberschatz & Galvin & Gagne: *Operating System Concepts*, s. 318–321,328. Eighth edition. Wiley, 2009. ISBN 978-0-470-12872-5. (englanniksi)
3. 1 2 3 4  William Stallings: *Operating System Internals and Design Principles*, s. 306–314,325. Seventh edition. Prentice Hall, 2012. ISBN 978-0-13-230998-1. (englanniksi)
4. ↑  Arpaci-Dusseau, Remzi H. & Arpaci-Dusseau, Andrea C.: Segmentation (PDF) *pages.cs.wisc.edu*. Viitattu 15.8.2019. (englanniksi)
5. ↑  Arpaci-Dusseau, Remzi H. & Arpaci-Dusseau, Andrea C.: Paging: Introduction (PDF) *pages.cs.wisc.edu*. Viitattu 1.3.2020. (englanniksi)
6. ↑  Arpaci-Dusseau, Remzi H. & Arpaci-Dusseau, Andrea C.: Beyond Physical Memory: Mechanisms (PDF) *pages.cs.wisc.edu*. Viitattu 23.10.2020. (englanniksi)
7. 1 2 3  5.6. Heap Memory *opendsa-server.cs.vt.edu*. Viitattu 5.10.2022. (englanniksi)
8. ↑  Stack *ece353.engr.wisc.edu*. Viitattu 19.9.2022. (englanniksi)
9. ↑
10. ↑  alloca *man7.org*. Viitattu 5.10.2022. (englanniksi)
11. ↑  Justifiably taboo: Avoiding malloc()/free() APIs in military/aerospace embedded code *mil-embedded.com*.
12. ↑  Philip Koopman: Stack Computers: 9.2 VIRTUAL MEMORY AND MEMORY PROTECTION *users.ece.cmu.edu*.  1989. Viitattu 5.10.2022. (englanniksi)
13. ↑  Jonathan Corbet: Memory protection keys *lwn.net*.  13.5.2015. Viitattu 5.10.2022. (englanniksi)
14. ↑  Memory Protection Keys *kernel.org*. Viitattu 5.10.2022. (englanniksi)

Aiheesta muualla
----------------

* C++-ohjelmointi: Osa 7 - Viittaukset, osoittimet ja dynaaminen muisti