Minden, amit tudnod kell a memóriaszivárgásokról az Androidban.
A Java egyik alapvető előnye, vagy pontosabban a JVM (Java Virtual Machine) egyik előnye a szemétgyűjtő (GC). Új objektumokat hozhatunk létre anélkül, hogy aggódnunk kellene a memóriából való felszabadításuk miatt. A szemétgyűjtő gondoskodik helyettünk a memória kiosztásáról és felszabadításáról.
Nem egészen! Megakadályozhatjuk, hogy a szemétgyűjtő felszabadítsa helyettünk a memóriát, ha nem értjük teljesen, hogyan működik a GC.
A kód írása anélkül, hogy jól értenénk, hogyan működik a GC, memóriaszivárgást okozhat az alkalmazásban. Ezek a szivárgások hatással lehetnek az alkalmazásunkra azáltal, hogy fel nem szabadított memóriát pazarolnak, és végül memórián kívüli kivételeket és késéseket okoznak.
- Mi az a memóriaszivárgás?
- Várj egy percet!!!🥴
- Heap & Stack
- Bővebben a Heap memóriáról
- Gondolkoztál már azon, hogy mi az alkalmazásod heap-mérete?
- Hogyan tudja ellenőrizni az alkalmazás heap méretét az eszközén?
- Hogyan működik ez a való világban?
- Mi történik, ha a módszerek megszűnnek?
- Következtetés
- Mi van a halommal?
- Hogyan működik a szemétgyűjtő?
- Mi történik, amikor a szemétgyűjtő fut?
- Mikor és hogyan történnek a memóriaszivárgások?
- Hogyan okozhatunk szivárgást?
- Hogyan okozhatunk szivárgást a szálak használatával?
- Reguláris áramlás
Mi az a memóriaszivárgás?
A fel nem használt objektumok memóriából való felszabadításának sikertelensége
A fel nem használt objektumok memóriából való felszabadításának sikertelensége azt jelenti, hogy vannak olyan fel nem használt objektumok az alkalmazásban, amelyeket a GC nem tud törölni a memóriából.
Ha a GC nem tudja törölni a fel nem használt objektumokat a memóriából, akkor bajban vagyunk. A nem használt objektumokat tartalmazó memóriaegység az alkalmazás végéig vagy (a módszer végéig) foglalt lesz.
A módszer végéig? Igen, így van. Kétféle szivárgásunk van, olyan szivárgások, amelyek az alkalmazás végéig foglalják a memóriaegységet, és olyan szivárgások, amelyek a metódus végéig foglalják a memóriaegységet. Az első egyértelmű. A második még további tisztázásra szorul. Vegyünk egy példát a magyarázathoz! Tegyük fel, hogy van egy X metódusunk. Az X metódus valamilyen hosszú futású feladatot végez a háttérben, és egy percig tart, amíg befejezi. Továbbá, az X metódus közben nem használt objektumokat tart. Ebben az esetben a memóriaegység foglalt lesz, és a nem használt objektumokat egy percig nem lehet törölni a feladat végéig. A metódus befejezése után a GC törölheti a fel nem használt objektumokat, és visszaszerezheti a memóriát.
Ezt szeretném, ha egyelőre tudnád, erre később még visszatérünk némi kóddal és vizualizációval. JÓ MÓKA LESZ. 👹😜
Várj egy percet!!!🥴
Mielőtt a kontextusra ugranánk, kezdjük az alapokkal.
A RAM, vagy Random access memory, az androidos készülékekben vagy számítógépekben található memória, amely az aktuálisan futó alkalmazások és azok adatainak tárolására szolgál.
A RAM két főszereplőjét fogom ismertetni, az első a Heap, a második pedig a Stack. Térjünk át a szórakoztató részre 🤩🍻.
Heap & Stack
Nem fogom túl hosszúra nyújtani. Térjünk rögtön a lényegre, egy rövid leírás, a Stack a statikus memória kiosztására szolgál, míg a Heap a dinamikus memória kiosztására. Csak ne feledjük, hogy mind a Heap, mind a Stack a RAM-ban tárolódik.
Bővebben a Heap memóriáról
A Java Heap memóriát a virtuális gép használja az objektumok kiosztására. Amikor létrehozunk egy objektumot, az mindig a heapben jön létre. A virtuális gépek, mint a JVM vagy a DVM, rendszeres szemétgyűjtést (GC) végeznek, így a már nem hivatkozott objektumok heap-memóriája elérhetővé válik a jövőbeli allokációkhoz.
A zökkenőmentes felhasználói élmény biztosítása érdekében az Android minden futó alkalmazás számára kemény korlátot állít be a heap méretére. A heap méretének korlátja készülékenként változik, és azon alapul, hogy az adott eszköz mennyi RAM-mal rendelkezik. Ha az alkalmazásod eléri ezt a heap-határt, és megpróbál több memóriát kiosztani, akkor OutOfMemoryError
jelzést kap, és leáll.
Gondolkoztál már azon, hogy mi az alkalmazásod heap-mérete?
Fedezzük fel ezt együtt. Az androidban van a Dalvik VM (DVM). A DVM egy egyedi, mobileszközökre optimalizált Java virtuális gép. Optimalizálja a virtuális gépet a memória, az akkumulátor élettartama és a teljesítmény szempontjából, és felelős az egyes alkalmazások memóriamennyiségének elosztásáért.
Beszéljünk a DVM két soráról:
- dalvik.vm.heapgrowthlimit: Ez a sor azon alapul, hogy a Dalvik hogyan indul el az alkalmazásod heapméretében. Ez az alapértelmezett heapméret minden alkalmazásnál. A maximum, amit az alkalmazásod elérhet!
- dalvik.vm.heapsize: Ez a sor a maximális heapméretet jelenti egy nagyobb heap esetén. Ezt úgy érheted el, hogy az alkalmazás manifesztjében nagyobb heapet kérsz az androidtól (android:largeHeap=”true”).
Ne használj nagyobb heapet az alkalmazásodban. Ezt CSAK akkor tedd meg, ha pontosan ismered ennek a lépésnek a mellékhatását. Itt adok neked elég információt, hogy tovább kutathass a témában.
Itt van egy táblázat, ami megmutatja, hogy milyen heap méretet kaptál az eszközöd RAM memóriája alapján:
+==========================+=========+=========+===================+
| DVM | 1GB RAM | 2GB RAM | 3GB RAM OR HIGHER |
+==========================+=========+=========+===================+
| DEFAULT(heapgrowthlimit) | 64m | 128m | 256m |
+--------------------------+---------+---------+-------------------+
| LARGE(heapsize) | 128m | 256m | 512m |
+--------------------------+---------+---------+-------------------+
Ne feledd, minél több ramod van, annál nagyobb lesz a heap mérete. észben tartva, hogy nem minden nagyobb rammal rendelkező eszköz 512m fölé megy, végezzen kutatást az eszközén, ha az eszközén több mint 3GB van, hogy lássa, ha a heap mérete nagyobb, mint 512m.
Hogyan tudja ellenőrizni az alkalmazás heap méretét az eszközén?
Az ActivityManager használatával. A maximális heap méretét futásidőben ellenőrizheti a getMemoryClass()
vagy getLargeMemoryClass()
metódusokkal (ha a nagy heap engedélyezve van).
- getMemoryClass(): Visszaadja az alapértelmezett maximális heapméretet.
- getLargeMemoryClass(): Visszaadja a maximálisan elérhető heap méretet, miután a manifesztben engedélyeztük a large heap flag-et.
ActivityManager am = getSystemService(ACTIVITY_SERVICE);
Log.d("XXX", "dalvik.vm.heapgrowthlimit: " + am.getMemoryClass());
Log.d("XXX", "dalvik.vm.heapsize: " + am.getLargeMemoryClass());
Hogyan működik ez a való világban?
Ezzel az egyszerű alkalmazással fogjuk megérteni, hogy mikor használjuk a heap-et és mikor a stack-et.
Az alábbi képen látható az alkalmazás heapjének és veremének ábrázolása, valamint az, hogy az egyes objektumok hova mutatnak és hol tárolódnak, amikor futtatjuk az alkalmazást.
Megnézzük az alkalmazás végrehajtását, megállítunk minden sort, elmagyarázzuk, hogy az alkalmazás mikor osztja ki az objektumokat, és mikor tárolja őket a heapben vagy a veremben. Azt is megnézzük, hogy az alkalmazás mikor szabadítja fel az objektumokat a veremről és a heapről.