Android-muistivuoto
Miten oikea elinkaaren hallinta voi estää Android-muistivuodot
OutOfMemoryException on yleinen ja turhauttava vika ja yksi tärkeimmistä syistä sovelluksen odottamattomaan sammumiseen.
”Miksi tämä tapahtuu nyt, jos sovellus toimi eilen moitteettomasti”?” Se on kysymys, joka hämmentää sekä aloittelevia että edistyneempiä Android-kehittäjiä kaikkialla maailmassa.
OutOfMemory Exceptionien mahdollisia syitä on useita, mutta yksi yleisimmistä on muistivuoto – muistin varaaminen sovelluksessa, jota ei koskaan vapauteta. Tässä artikkelissa kerrotaan, miten tämä riski voidaan minimoida tehokkaalla elinkaarenhallinnalla – tärkeä mutta usein unohdettu osa kehitysprosessia.
TL;DR
Tässä artikkelissa käsittelemme:
- Androidin muistivuodon syyt
- Perusaskeleet muistivuodon estämiseksi
- Edistyneemmät elinkaarenhallinnan muodot
- Työkalut, joilla voit hallita tuotteesi elinkaarta
Miksi RAM-muistivuoto tapahtuu Androidissa?
Ongelma on yksinkertainen. Tietyillä objekteilla pitäisi olla vain kiinteä käyttöikä, ja kun niiden käyttöikä on ohi, ne on poistettava.
Teoriassa tämä muisti pitäisi hävittää, kun prosessi lopetetaan onStop- tai onDestroy-ohjelmalla. Objektiin viittaamisen väärinkäyttö voi kuitenkin estää roskienkerääjää poistamasta käyttämättömiä objekteja. Esimerkiksi: Jos käyttämätön objekti A viittaa käyttämättömään objektiin B, päädytään kahteen tarpeettomaan objektiin, joita roskienkerääjä ei koskaan poista, koska ne viittaavat toisiinsa.
Yleisiä temppuja, joilla tämä voidaan estää
Kehittäjät voivat ryhtyä useisiin toimenpiteisiin estääkseen kuolleiden aktiviteettien jäämisen muistiin.
- Registeröi/poista BroadcastReceiverit onResume()/onPause()- tai onStart()/onStop()-toiminnoissa
- ÄLÄ KOSKAAN käytä staattisia muuttujia Näkymille/Aktiviteeteille/Konteksteille
- Singletonien, jotka tarvitsevat viitteitä Kontekstiin, tulisi käyttää applicationContext()-ominaisuutta, tai paketoida se WeakReference-ominaisuudeksi
- Varoittelehan anonyymejä ja muita kuinstaattisten sisäisten luokkien kanssa, koska niillä on implisiittinen viittaus ympäröivään luokkaan.
- Käytä staattisia sisäisiä luokkia anonyymien sijaan, jos ne aikovat elää vanhempaa luokkaa pidempään (kuten Handlers).
- Jos sisäinen tai anonyymi luokka on peruutettavissa (kuten AsyncTask, Thread, RxSubscriptions), peruuta se, kun aktiviteetti tuhotaan.
Androidin elinkaaritietoiset komponentit
Kun olet suorittanut yllä olevat perusaskeleet, on aika käsitellä jotain paljon tärkeämpää: sovelluksen aktiviteettien elinkaari. Jos emme hallitse elinkaarta oikein, päädymme roikkumaan muistissa, kun sitä ei enää tarvita.
Tässä on monia eri tehtäviä. Jokaisen aktiviteetin kohdalla meidän on keskeytettävä säikeet, hankkiuduttava eroon RxJavan tilauksista, peruutettava AsyncTask-viittaukset ja varmistettava, että tämän aktiviteetin (ja kaikkien muiden siihen liitettyjen aktiviteettien) viittaus poistetaan oikein. Kaikki nämä tehtävät voivat viedä valtavan määrän kehittäjän aikaa.
Asiasta tekee vielä monimutkaisemman Model View Presenter (MVP), arkkitehtuurimalli, jota käytetään usein Androidin käyttöliittymän rakentamiseen. MVP on kuitenkin hyödyllinen, jotta liiketoimintalogiikka voidaan irrottaa Näkymästä.
MVP-mallissa sekä Näkymä että Presenter ovat abstrakteja toteutuksia niiden välisestä käyttäytymissopimuksesta. Yleisin tapa toteuttaa MVP on käyttää Activity/Fragmenttia näkymän toteutuksena ja yksinkertaista toteutusta Presenterille, joka on tottunut saamaan View-viittauksen.
Siten päädymme siihen, että meillä on View, jolla on Presenter-viittaus, ja Presenter, jolla on View-viittaus (Vinkki: Meillä on tässä potentiaalinen vuoto).
Kun otetaan huomioon nämä mahdolliset vaikeudet, on tärkeää, että otamme käyttöön asianmukaisen hallintarakenteen, jolla poistamme elinkaaren aikana syntyvän ylimääräisen muistin. Tähän on olemassa useita hyväksi todettuja tapoja:
Leenkiertotietoisten komponenttien luominen käyttämällä Android Arch Lifecycle -ohjelmaa Android Studiossa
Leenkiertotietoiset komponentit ovat älykkäitä. Ne voivat reagoida toisen komponentin, kuten aktiviteettien tai fragmenttien, elinkaaren tilan muutokseen esimerkiksi poistamalla muistia. Näin koodi on kevyempää ja paljon muistitehokkaampaa.
Arch Lifecycle on Androidin uusi kirjasto, joka tarjoaa joukon työkaluja elinkaaritietoisten komponenttien rakentamiseen. Kirjasto toimii abstraktilla tavalla, joten elinkaaren omistajien ei tarvitse enää huolehtia tiettyjen tehtävien ja aktiviteettien elinkaaren hallinnasta.
Arch Lifecyklen tärkeimmät työkalut ja määritelmät ovat seuraavat:
- LifeCycle: Lajittelujärjestelmä, joka määrittelee, millä objekteilla on Android-elinkaari, ja jonka avulla niitä voidaan sitten seurata.
- LifecycleObserver: Säännöllinen rajapinta, joka valvoo jokaista objektia, jolla on Androidin elinkaari, käyttäen yksinkertaista kaavaa kunkin keskeisen elinkaaritapahtuman käsittelyyn.
- @OnLifecycleEvent: Annotaatio, jota voidaan käyttää luokissa, jotka toteuttavat LifecycleObserver-rajapinnan. Sen avulla voidaan asettaa avaimen elinkaaritapahtumia, jotka käynnistävät annotoidun metodin aina, kun se käynnistetään. Tässä on luettelo kaikista asetettavista tapahtumista:
- ON_ANY
- ON_CREATE
- ON_DESTROY
- ON_PAUSE
- ON_RESUME
- ON_START
- ON_STOP
.
- LifecycleOwner on oletuksena toteutettu jokaiselle Android-komponentille, jonka elinkaarta voidaan hallita, ja antaa kehittäjälle hallinnan jokaisesta tapahtumasta.
Käyttämällä näitä työkaluja pystymme lähettämään kaikki puhtaat tehtävät omistajilleen (meidän tapauksessamme esittelijöille), joten meillä on puhdasta, irtikytkettyä koodia, jossa ei ole vuotoja (ainakaan esittelijäkerroksessa).
Tässä on superbasistoteutus, joka näyttää, mistä puhumme:
interface View: MVPView, LifecycleOwnerclass RandomPresenter : Presenter<View>, LifecycleObserver { private lateinit var view: View override fun attachView(view: View) { this.view = view view.lifecycle.addObserver(this) } @OnLifecycleEvent(Lifecycle.Event.On_DESTROY) fun onClear() {//TODO: clean }
Androidin Arch-näkymämallien käyttäminen esittelijöinä ja LiveDatana
Toinen tapa välttää elinkaaren vääränlaisesta hallinnasta johtuvat muistivuodot on käyttää Arch-komponenttikirjaston uusia ViewModels-malleja.
Näkymämalli on abstrakti luokka, joka toteuttaa yhden ainoan onClear-nimisen funktion, jota kutsutaan automaattisesti, kun tietty objekti pitää poistaa. ViewModel luodaan kehyksen toimesta ja se liitetään luojansa elinkaareen (lisäbonuksena se on superhelppo injektoida Daggerin avulla.)
ViewModelin käytön lisäksi LiveData tarjoaa myös elintärkeän viestintäkanavan. Tuote noudattaa reaktiivista, helposti havainnoitavaa mallia, mikä tarkoittaa, että yksittäiset objektit voivat havainnoida sitä (luoden vähemmän kytkeytynyttä koodia).
Hienoa tässä on se, että LiveDataa voi havainnoida elinkaaren omistaja, joten tiedonsiirto hoidetaan aina elinkaaren toimesta -ja voimme varmistaa, että kaikki viittaukset säilyvät niitä käytettäessä.
LeakCanaryn ja Bugfenderin käyttäminen
Edellä mainittujen vaiheiden lisäksi halusimme suositella kahta tärkeää työkalua: LeakCanaryn, suositun työkalun vuotojen seurantaan, ja oman Bugfenderin.
LeakCanary on muistinhavaintokirjasto Androidille ja Javalle. Se on avoimeen lähdekoodiin perustuva, joten sen takana on valtava yhteisö, ja se ei vain kerro vuodosta – se ilmoittaa myös sen todennäköisen syyn.
Bugfender, etäloggaustyökalumme, mahdollistaa yksittäisten LeakTraces-ajojen debuggaamisen ja laajentaa DisplayLeakService-nimistä luokkaa, joka ilmoittaa meille, kun vuoto ilmenee. Sitten voimme helposti lokata sen Bugfenderillä.
public class LeakUploadService extends DisplayLeakService { override fun afterDefaultHandling(heapDump: HeapDump, result: AnalysisResult, leakInfo: String) { if (result.leakFound) { Bugfender.d("LeakCanary", result.toString()) } }}
Käyttäjät saavat lisäksi kaikki Bugfenderin muut edut, kuten 24/7 lokitallennuksen (myös silloin, kun laite on offline-tilassa), sisäänrakennetun kaatumisraportoinnin ja helppokäyttöisen web-konsolin, jonka avulla voidaan porautua yksittäisiin laitteisiin parempaa asiakaspalvelua varten.
Lisätietoa Bugfenderistä saat napsauttamalla tästä.
Klikkaa tästä.
Leave a Reply