A memóriakezelés áttekintése

Az Android Runtime (ART) és a Dalvik virtuális gép a memóriakezeléshez lapozást és memóriatérképezést (mmapping) használ. Ez azt jelenti, hogy minden memória, amelyet egy alkalmazás módosít – akár új objektumok kiosztásával, akár mmapped oldalak érintésével – a RAM-ban marad, és nem lapozható ki. A memória felszabadításának egyetlen módja az alkalmazás által birtokolt objektumhivatkozások felszabadítása, így a memória elérhetővé válik a szemétgyűjtő számára. Ez egy kivételtől eltekintve: a módosítás nélkül mmapolt fájlok, például a kód, kihelyezhetők a RAM-ból, ha a rendszer máshol akarja használni ezt a memóriát.

Ez az oldal elmagyarázza, hogyan kezeli az Android az alkalmazásfolyamatokat és a memória kiosztását. További információt arról, hogyan kezelheti hatékonyabban a memóriát az alkalmazásában, az Alkalmazása memóriájának kezelése című fejezetben talál.

Szemétgyűjtés

Egy kezelt memóriakörnyezet, például az ART vagy a Dalvik virtuális gép, nyomon követi az egyes memóriafoglalásokat. Amint megállapítja, hogy egy memóriadarabot már nem használ a program, felszabadítja azt vissza a halomra, a programozó beavatkozása nélkül. A kezelt memóriakörnyezetben a nem használt memória visszaszerzésének mechanizmusát szemétgyűjtésnek nevezzük. A szemétgyűjtésnek két célja van: megtalálni a programban azokat az adatobjektumokat, amelyekhez a jövőben nem lehet hozzáférni; és visszaszerezni az ezen objektumok által használt erőforrásokat.

Az Android memóriaheapje generációs, ami azt jelenti, hogy a kiosztásoknak különböző vödrei vannak, amelyeket a kiosztott objektum várható élettartama és mérete alapján követ. Például a nemrég allokált objektumok a Young generációba tartoznak. Ha egy objektum elég sokáig aktív marad, átkerülhet egy régebbi generációba, majd az állandó generációba.

Minden heap-generációnak megvan a saját dedikált felső határa az ott lévő objektumok által elfoglalható memória mennyiségére. Bármikor, amikor egy generáció kezd megtelni, a rendszer szemétgyűjtési eseményt hajt végre, hogy megpróbálja felszabadítani a memóriát. A szemétgyűjtés időtartama attól függ, hogy melyik generációba gyűjti az objektumokat, és hogy az egyes generációkban hány aktív objektum van.

Bár a szemétgyűjtés elég gyors lehet, mégis hatással lehet az alkalmazás teljesítményére. A szemétgyűjtési esemény bekövetkezésének idejét általában nem a kódodból irányíthatod. A rendszernek van egy futó kritériumkészlete annak meghatározására, hogy mikor kell elvégezni a szemétgyűjtést. Amikor a kritériumok teljesülnek, a rendszer leállítja a folyamat végrehajtását, és megkezdi a szemétgyűjtést. Ha a szemétgyűjtés egy intenzív feldolgozási ciklus, például egy animáció vagy zenelejátszás közben történik, az megnövelheti a feldolgozási időt. Ez a növekedés potenciálisan túllépheti az alkalmazásban a hatékony és zökkenőmentes képkocka-visszaadáshoz ajánlott 16 ms-os küszöbértéket.

Emellett a kódfolyamat olyan típusú munkát végezhet, amely miatt a szemétgyűjtési események gyakrabban fordulnak elő, vagy a szokásosnál hosszabb ideig tartanak. Ha például egy alfa blending animáció minden egyes képkockája során egy for-loop legbelső részében több objektumot allokál, akkor előfordulhat, hogy sok objektummal szennyezi a memóriahalmazt. Ilyen körülmények között a szemétgyűjtő több szemétgyűjtési eseményt hajt végre, és ez ronthatja az alkalmazás teljesítményét.

A szemétgyűjtéssel kapcsolatos további általános információkért lásd: Szemétgyűjtés.

Memória megosztása

Annak érdekében, hogy minden szükséges dolog elférjen a RAM-ban, az Android megpróbálja megosztani a RAM-oldalakat a folyamatok között. Ezt a következő módokon teheti meg:

  • Minden egyes alkalmazásfolyamat egy meglévő, Zygote nevű folyamatból ágazik el. A Zygote folyamat a rendszer indításakor elindul, és betölti a közös keretrendszer kódját és erőforrásait (például a tevékenységtémákat). Egy új alkalmazásfolyamat indításához a rendszer elágazik a Zygote folyamattól, majd betölti és futtatja az alkalmazás kódját az új folyamatban. Ez a megközelítés lehetővé teszi, hogy a keretrendszer kódjához és erőforrásaihoz rendelt RAM-lapok nagy részét az összes alkalmazásfolyamat megoszthassa.
  • A legtöbb statikus adat mmappinggel kerül egy folyamatba. Ez a technika lehetővé teszi, hogy az adatok megoszthatók legyenek a folyamatok között, és szükség esetén ki is lapozhatók. A statikus adatok példái közé tartoznak: Dalvik kód (azáltal, hogy egy előre linkelt .odex fájlban helyezzük el a közvetlen mmappinghez), az alkalmazás erőforrásai (azáltal, hogy az erőforrástáblát úgy alakítjuk ki, hogy az mmappingelhető struktúra legyen, és az APK zip-bejegyzéseit összehangoljuk), valamint a hagyományos projektelemek, például a natív kód .so fájlokban.
  • Az Android sok helyen ugyanazt a dinamikus RAM-ot osztja meg a folyamatok között, explicit módon kiosztott megosztott memóriarégiók segítségével (akár ashmem vagy gralloc segítségével). Például az ablakfelületek megosztott memóriát használnak az alkalmazás és a képernyő kompozitor között, a kurzorpufferek pedig megosztott memóriát használnak a tartalomszolgáltató és az ügyfél között.

A megosztott memória kiterjedt használata miatt az alkalmazás által használt memória mennyiségének meghatározása körültekintést igényel. Az alkalmazás memóriahasználatának megfelelő meghatározására szolgáló technikákat a RAM-használat vizsgálata című fejezet tárgyalja.

Az alkalmazás memóriájának kiosztása és visszakövetelése

A Dalvik-heap minden egyes alkalmazásfolyamat számára egyetlen virtuális memóriatartományra van korlátozva. Ez határozza meg a logikai halom méretét, amely szükség szerint nőhet, de csak a rendszer által az egyes alkalmazások számára meghatározott határig.

A halom logikai mérete nem azonos a halom által használt fizikai memória mennyiségével. Az Android az alkalmazás heapjének vizsgálatakor kiszámítja az arányos készletméret (PSS) nevű értéket, amely figyelembe veszi a más folyamatokkal megosztott piszkos és tiszta oldalakat is – de csak olyan mennyiségben, amely arányos azzal, hogy hány alkalmazás osztozik az adott RAM-on. Ezt a (PSS) végösszeget tekinti a rendszer az Ön fizikai memóriaterületének. A PSS-ről további információkat a RAM-használat vizsgálata című útmutatóban talál.

A Dalvik heap nem tömöríti a heap logikai méretét, ami azt jelenti, hogy az Android nem defragmentálja a heapet a hely lezárása érdekében. Az Android csak akkor tudja zsugorítani a logikai halom méretét, ha a halom végén van kihasználatlan hely. A rendszer azonban így is képes csökkenteni a halom által használt fizikai memóriát. A szemétgyűjtés után a Dalvik bejárja a heapet, és megtalálja a nem használt oldalakat, majd ezeket az oldalakat a madvise segítségével visszaadja a kernelnek. Így a nagy darabok párosított kiosztásának és visszavonásának az összes (vagy majdnem az összes) használt fizikai memória visszanyerését kell eredményeznie. A kis kiosztásokból származó memória visszakövetelése azonban sokkal kevésbé hatékony lehet, mivel a kis kiosztáshoz használt oldal még mindig megosztható valami mással, amit még nem szabadítottak fel.

Az alkalmazások memóriájának korlátozása

A funkcionális többfeladatos környezet fenntartása érdekében az Android minden alkalmazás számára kemény korlátot állít be a heap méretére. A pontos heapméret-korlátozás készülékenként változik, attól függően, hogy mennyi RAM áll a készülék rendelkezésére összességében. Ha az alkalmazás elérte a heap-kapacitást, és megpróbál több memóriát kiosztani, akkor OutOfMemoryError.

Bizonyos esetekben érdemes lekérdezni a rendszert, hogy pontosan meghatározzuk, mennyi heap-terület áll rendelkezésre az aktuális eszközön – például annak meghatározásához, hogy mennyi adatot lehet biztonságosan a gyorsítótárban tartani. Ezt a számot a getMemoryClass() meghívásával kérdezheti le a rendszertől. Ez a módszer egy egész számot ad vissza, amely jelzi, hogy hány megabájt áll rendelkezésre az alkalmazás halmaza számára.

Alkalmazások váltása

Amikor a felhasználók alkalmazások között váltanak, az Android a nem előtérben lévő – azaz a felhasználó számára nem látható vagy előtérben lévő szolgáltatást, például zenelejátszást futtató – alkalmazásokat a gyorsítótárban tartja. Például amikor a felhasználó először indít el egy alkalmazást, létrejön egy folyamat hozzá; de amikor a felhasználó elhagyja az alkalmazást, ez a folyamat nem szűnik meg. A rendszer a folyamatot a gyorsítótárban tartja. Ha a felhasználó később visszatér az alkalmazáshoz, a rendszer újra felhasználja a folyamatot, ezáltal gyorsabbá teszi az alkalmazás váltását.

Ha az alkalmazásnak van egy gyorsítótárban tárolt folyamata, és az olyan erőforrásokat tart vissza, amelyekre jelenleg nincs szüksége, akkor az alkalmazás – még akkor is, ha a felhasználó nem használja – hatással van a rendszer általános teljesítményére. Amikor a rendszer kifogy az erőforrásokból, például a memóriából, megöli a gyorsítótárban lévő folyamatokat. A rendszer számon tartja azokat a folyamatokat is, amelyek a legtöbb memóriát tartják meg, és a RAM felszabadítása érdekében meg tudja őket szüntetni.

Megjegyzés: Minél kevesebb memóriát fogyaszt az alkalmazás, amíg a gyorsítótárban van, annál nagyobb az esélye, hogy nem öli meg, és gyorsan folytatódhat. A pillanatnyi rendszerkövetelményektől függően azonban lehetséges, hogy a gyorsítótárban lévő folyamatok bármikor megszakadnak, függetlenül az erőforrás-kihasználtságuktól.

További információkat arról, hogy a folyamatok hogyan kerülnek a gyorsítótárba, amíg nem az előtérben futnak, és hogyan dönti el az Android, hogy melyiket lehet megölni, a Folyamatok és szálak útmutatóban találsz.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük