On syytä pitää mielessä, että vaikka tämä työkalu voi olla erittäin hyödyllinen, kun etsitään viittauksia epäiltyyn vuotoon, sen käyttö tuntemattomien vuotojen löytämiseen voi olla melko vaikeaa ja monimutkaista, ja se vaatii melko paljon analyysiä. Sanotaanko näin, että jos hallitset sen – se on loistava työkalu vyölläsi!
LeakCanary
Toinen tapa löytää muistivuotoja on käyttää Leak Canarya, joka on Squaren luoma kirjasto, jonka avulla voit havaita muistivuotoja. Se toimii käyttämällä ObjectWatcher
-luokkaa, joka pitää heikkoja viittauksia tuhottuihin objekteihin kasassa. Jos viittausta ei tyhjennetä seuraavien viiden sekunnin aikana ja Garbage Collector on ajettu, objektin katsotaan säilyneen ja se kirjaa tämän mahdollisena muistivuotona logcatiin. Aika fiksua, eikö?
Aloittaaksesi, lisää vain kirjasto riippuvuuksien sisällä build.gradle-tiedostoosi, synkronoi ja käännä.
Heti kun käynnistät sovelluksen, näet LeakCanaryn tulostuksen logcatissa, kun se tarkkailee instansseja ja säilyttää objekteja. Vuodon käynnistämiseksi lisäsin pari uutta tehtävää TaskManager-sovellukseeni. Pian sen jälkeen sain LeakCanarylta tämän ilmoituksen, joka viittaa mahdolliseen vuotoon!
Klikkaa ilmoitusta ”dump heap” tutkiaksesi potentiaalista vuotoa, ja tämä valintaikkuna tulee näkyviin sovelluksessa.
LeakCanary analysoi sen jälkeen kasan paikantamalla pidätetyt objektit ja löytää vuotojäljen, joka on polku viittauksista kuhunkin pidätettyyn objektiin. Kun tämä on tehty, näytetään ilmoitus, jossa esitetään yhteenveto pidätettyjen objektien ja vuotojen määrästä.
Näyttää siltä, että se löysi vuotomme! Jos klikkaamme sitä, näemme koko vuotojäljen:
Se kertoo meille, että TaskActivity vuotaa ja alleviivatut viittaukset osoittavat jäljen, se vuotaa mContext
:stä SingletonExample
:iin mContext
:sta SingletonExample
:iin – kuulostaa tutulta! Nyt tiedämme, miten vuoto löydetään LeakCanaryn avulla. 😃
Muistivuodon välttäminen
Nyt kun olemme löytäneet muistivuodon, miten voimme välttää niitä tulevaisuudessa? Alla on joitakin yleisimpiä syitä ja malleja.
Lähetysvastaanottimet
Lähetysvastaanottimia voidaan käyttää kuuntelemaan koko järjestelmän laajuisia lähetystapahtumia (broadcast events) tai -intenttejä (intents), jotka ilmaisevat laitetietoja, kuten alhaisen akun varauksen, päivämäärän ja yhteyksien muutokset – esimerkiksi sen, että lentokonetila on kytketty pois päältä. Niitä käytettäessä on muistettava poistaa broadcast-vastaanottimien rekisteröinti, sillä muuten jää väistämättä jäljelle viittaus toimintaan.
Miten se vältetään:
Tämä kuvio löytyy myös asyncTaskista, TimerTaskista ja säikeistä, jotka täytyy peruuttaa onDestroy()
:ssä vuodon välttämiseksi.
Konteksti Singleton-luokkaan
Joskus meidän täytyy siirtää konteksti aktiviteetista Singleton-luokkaan. Esimerkki tästä olisi utils-luokka, jossa meidän täytyy käyttää resursseja, palveluita tai sisäisiä tiedostoja. Kontekstin välittäminen tarkoittaa kuitenkin sitä, että pidämme väistämättä kiinni viitteestä aktiviteettiin.
Miten se vältetään: Sen sijaan, että välitämme this
aktiviteetista, voimme välittää sovelluskontekstin, jos se on käytettävissä (jos haluat oppia lisää siitä, milloin mitäkin kontekstia kannattaa käyttää, tämä artikkeli oli mielestäni todella hyödyllinen!). Vaihtoehtoinen ratkaisu on varmistaa, että asetamme Singleton-kontekstin nollaksi aktiviteetin onDestroy()
-metodin sisällä.
Staattiset viittaukset
Näkymän tai aktiviteetin viittaaminen staattisena tarkoittaa, että viittausta aktiviteettiin ei kerätä roskiin. Tätä tulisi yksinkertaisesti välttää aina.
Miten sitä vältetään: onDestroy().
Sisäluokkien sisäiset viittaukset
Sisäluokat aiheuttavat usein vuotoja pitämällä implisiittistä viittausta ulompaan luokkaan. Tämä tapahtuu luokan muuttuja on ilmoitettu staattiseksi tai jos luokkaa itseään ei ole ilmoitettu staattiseksi. Hämmentävää? Kyllä, mutta se on helppo välttää, jos noudatamme alla olevaa yksinkertaista sääntöä.
Miten se vältetään: Tee sisäisestä luokasta staattinen, jotta vältät viittauksen pitämisen ulkoiseen luokkaan, äläkä koskaan luo sisäisen luokan staattista muuttujaa. Sama pätee anonyymeihin luokkiin.
Se on siinä! Toivottavasti opit jotain muistivuodoista ja niiden välttämisestä. Hyvää koodausta! 😄
Tässä on joukko artikkeleita ja dokumentaatiota, joita pidin erityisen hyödyllisinä oppiessani muistivuodoista: