2.40. Muisti ja roskienkeruu¶
MicroPython hallinnoi muistia samalla tavalla kuin CPython: jokainen olio elää keossa (heap), ja roskienkerääjä (garbage collector, GC) vapauttaa oliot, joihin mikään ei enää viittaa. Laitteessa, jossa on muutama sata kilotavua RAM-muistia, huomion kiinnittäminen siihen, miten kekoa käytetään, on toisinaan välttämätöntä; pöytäkoneen Pythonissa harvoin.
2.40.1. Keko¶
Keko on se RAM-muistin alue – useimmissa OpenMV-kameroissa todellisuudessa jaettu useamman kuin yhden fyysisen muistivarannon kesken – jonka ajonaikainen ympäristö jakaa Python-olioille. Joka kerta kun Python-lauseke luo uuden olion (listan, merkkijonon, dictin, monikon, mitä tahansa, joka ei ole pieni kokonaisluku tai singleton), keosta tulee tavulohko sen säilyttämiseen. Kun GC huomaa, että olio on tavoittamattomissa, se palauttaa lohkon siihen vapaaseen varantoon, mistä se tuli.
Kaksi moduulin gc funktiota kannattaa tuntea:
gc.mem_free()– likimääräinen vapaiden tavujen määrä keossa juuri nyt.gc.collect()– suorita keruusykli välittömästi sen sijaan, että odottaisi ajonaikaisen ympäristön käynnistävän sen.
import gc
print("before:", gc.mem_free())
big = [0] * 10000
print("after :", gc.mem_free())
del big
gc.collect()
print("freed :", gc.mem_free())
Tarkat luvut riippuvat käännöksestä; muutoksen suunta on se, millä on väliä: suurten asioiden varaaminen vähentää arvoa mem_free, ja viittausten pudottaminen sekä gc.collect antaa keon takaisin.
2.40.2. Pirstoutuminen¶
Vapaa varanto ei ole taianomaisesti yhtenäinen. Kun oliot tulevat ja menevät eri elinaikoina, vapaa tila murtuu yhä pienemmiksi paloiksi, vaikka sen kokonaiskoko on edelleen suuri. Suurimman yksittäisen vapaan palan kokoa suuremman olion varaaminen epäonnistuu poikkeuksella MemoryError – vaikka teknisesti vapaata RAM-muistia on yhteensä tarpeeksi.
Sama kokonaismäärä vapaata RAM-muistia voi pitää sisällään suuren puskurin (vasemmalla) tai kieltäytyä siitä (oikealla) riippuen siitä, kuinka pirstoutunut se on.¶
Pirstoutuminen on enimmäkseen huoli pitkään ajettavissa skripteissä, jotka jatkavat erikokoisten puskurien varaamista ja vapauttamista. Yksittäinen tehokkain lieventämiskeino on esivarata pitkäikäiset puskurit lähellä ohjelman alkua, ennen kuin lukuisat lyhytikäiset varaukset ovat ehtineet hajottaa niitä.
2.40.3. Esivaraus¶
Kaksi mallia saa keon käyttäytymään:
Varaa kiinteäkokoiset puskurit kerran ja käytä niitä uudelleen sen sijaan, että rakentaisit uuden listan tai
bytearray-olion jokaista iteraatiota kohti.Vedä vakiot ja hakutaulukot ulos sisäsilmukoista, jotta ne luodaan kerran.
buf = bytearray(64) # one allocation, reused below
def fill(value):
for i in range(len(buf)):
buf[i] = value
fill(0)
fill(255)
Vertaa versioon, joka luo uuden bytearray-olion silmukan sisällä: jokainen iteraatio tuottaa roskaa, joka GC:n on siivottava myöhemmin. Esivarattu versio ei tuota lainkaan roskaa.
2.40.4. Milloin kutsua gc.collect¶
gc.collect() on normaalisti automaattinen – ajonaikainen ympäristö käynnistää sen, kun varaukset eivät löydä tarpeeksi vapaata muistia. Sen kutsuminen käsin on hyödyllistä kahdessa tilanteessa:
Heti suuren olioerän mentyä pois näkyvyysalueelta, jotta ne vapautuvat välittömästi sen sijaan, että odotettaisiin seuraavan varauksen maksavan hinnan.
Juuri ennen osiota, joka tarvitsee tunnetun enimmäismäärän vapaata muistia, jotta vältetään GC:n laukeaminen kesken aikakriittisen toiminnon.
gc.collect-kutsujen ripottelu kaikkialle ei tee ohjelmasta nopeampaa – keruu itsessään vie aikaa. Käytä sitä harkiten, kohdissa, joissa aikataulemattoman keruun hinta olisi pahempi kuin sellaisen, jonka ajoit tarkoituksella.