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.