Android Runtime (ART) och den virtuella maskinen Dalvik använder paging och memory-mapping (mmapping) för att hantera minnet. Detta innebär att allt minne som en app ändrar – antingen genom att allokera nya objekt eller röra mmappade sidor – stannar kvar i RAM och kan inte pageras ut. Det enda sättet att frigöra minne från en app är att frigöra objektreferenser som appen innehar, vilket gör minnet tillgängligt för skräpplockaren. Detta med ett undantag: alla filer som mappas in utan ändring, t.ex. kod, kan pageras ut ur RAM om systemet vill använda minnet någon annanstans.
Den här sidan förklarar hur Android hanterar app-processer och minnesallokering. Mer information om hur du hanterar minnet mer effektivt i din app finns i Hantera appens minne.
Garbage collection
En hanterad minnesmiljö, som den virtuella maskinen ART eller Dalvik, håller reda på varje minnesallokering. När den fastställer att en del av minnet inte längre används av programmet frigör den den tillbaka till heap, utan något ingripande från programmeraren. Mekanismen för att återta oanvänt minne i en hanterad minnesmiljö kallas garbage collection. Garbage collection har två mål: att hitta dataobjekt i ett program som det inte går att komma åt i framtiden och att återta de resurser som används av dessa objekt.
Androids minneshög är generationsbaserad, vilket innebär att det finns olika hinkar med allokeringar som den spårar, baserat på den förväntade livslängden och storleken på ett objekt som allokeras. Nyligen allokerade objekt hör till exempel hemma i generationen Young. När ett objekt förblir aktivt tillräckligt länge kan det befordras till en äldre generation, följt av en permanent generation.
Varje heapgeneration har sin egen dedikerade övre gräns för hur mycket minne som objekten där kan uppta. Varje gång en generation börjar fyllas upp utför systemet en skräpplockningshändelse i ett försök att frigöra minne. Hur länge skräpplockningen varar beror på vilken generation av objekt den samlar in och hur många aktiva objekt som finns i varje generation.
Även om skräpplockningen kan vara ganska snabb kan den ändå påverka appens prestanda. Du kan i allmänhet inte styra när en garbage collection-händelse inträffar från din kod. Systemet har en löpande uppsättning kriterier för att avgöra när garbage collection ska utföras. När kriterierna är uppfyllda slutar systemet att exekvera processen och påbörjar skräpinsamlingen. Om skräpplockning sker mitt i en intensiv bearbetningsslinga, t.ex. en animation eller under musikuppspelning, kan det öka bearbetningstiden. Denna ökning kan potentiellt driva kodutförandet i din app över den rekommenderade tröskeln på 16 ms för effektiv och smidig bildrendering.
Det kan dessutom hända att ditt kodflöde utför arbetsuppgifter som gör att skräpinsamlingshändelser inträffar oftare eller att de pågår längre än normalt. Om du till exempel allokerar flera objekt i den innersta delen av en for-slinga under varje bild i en animering med alfabetisk blandning kan det hända att du förorenar din minneshög med många objekt. I det fallet utför skräpplockaren flera skräpplockningshändelser och kan försämra prestandan för din app.
För mer allmän information om skräpplockning, se Skräpplockning.
Dela minne
För att få plats med allt som behövs i RAM försöker Android dela RAM-sidor mellan processerna. Det kan göra det på följande sätt:
- Varje app-process är forkad från en befintlig process som heter Zygote. Zygote-processen startar när systemet startar och laddar in gemensam ramkod och resurser (t.ex. aktivitetsteman). För att starta en ny app-process forkar systemet Zygote-processen och laddar sedan in och kör appens kod i den nya processen. Detta tillvägagångssätt gör att de flesta RAM-sidor som tilldelas för ramkod och resurser kan delas mellan alla app-processer.
- De flesta statiska data mmappas in i en process. Den här tekniken gör det möjligt att dela data mellan processer och gör det också möjligt att paga ut dem vid behov. Exempel på statiska data är: Dalvik-kod (genom att placera den i en länkad
.odex
-fil för direkt mappning), appresurser (genom att utforma resurstabellen så att den är en struktur som kan mappas och genom att anpassa zip-posterna i APK:n) och traditionella projektelement som inhemsk kod i.so
-filer. - På många ställen delar Android samma dynamiska RAM-minne mellan processer med hjälp av explicit tilldelade delade minnesregioner (antingen med ashmem eller gralloc). Till exempel använder fönsterytor delat minne mellan appen och skärmkompositorn, och markörbuffertar använder delat minne mellan innehållsleverantören och klienten.
På grund av den omfattande användningen av delat minne krävs noggrannhet för att avgöra hur mycket minne din app använder. Tekniker för att korrekt fastställa appens minnesanvändning diskuteras i Undersöka din RAM-användning.
Allokera och återkräva appens minne
Dalviks heap är begränsad till ett enda virtuellt minnesområde för varje app-process. Detta definierar den logiska heapstorleken, som kan växa efter behov men bara upp till en gräns som systemet definierar för varje app.
Den logiska storleken på heap är inte densamma som mängden fysiskt minne som används av heap. När Android inspekterar din apps heap beräknar det ett värde som kallas Proportional Set Size (PSS), som tar hänsyn till både smutsiga och rena sidor som delas med andra processer – men bara i en mängd som är proportionell mot hur många appar som delar det RAM-minnet. Denna totalsumma (PSS) är vad systemet anser vara ditt fysiska minnesavtryck. Mer information om PSS finns i guiden Undersök din RAM-användning.
Dalvik-heap komprimerar inte den logiska storleken på heap, vilket innebär att Android inte defragmenterar heap för att stänga upp utrymme. Android kan endast krympa den logiska heapstorleken när det finns oanvänt utrymme i slutet av heapen. Systemet kan dock fortfarande minska det fysiska minnet som används av heap. Efter skräpplockning går Dalvik igenom heap och hittar oanvända sidor och returnerar sedan dessa sidor till kärnan med hjälp av madvise. Så parvisa allokeringar och avallokeringar av stora delar bör resultera i att allt (eller nästan allt) fysiskt minne som används återvinns. Återtagande av minne från små allokeringar kan dock vara mycket mindre effektivt eftersom den sida som används för en liten allokering fortfarande kan delas med något annat som ännu inte har frigjorts.
Begränsning av appminne
För att bibehålla en funktionell multitasking-miljö sätter Android en hård gräns för heapstorleken för varje app. Den exakta gränsen för heapstorlek varierar mellan enheterna baserat på hur mycket RAM som enheten har tillgängligt totalt sett. Om din app har nått heap-kapaciteten och försöker allokera mer minne kan den få en OutOfMemoryError
.
I vissa fall kan du vilja fråga systemet för att avgöra exakt hur mycket heap-utrymme du har tillgängligt på den aktuella enheten – till exempel för att avgöra hur mycket data det är säkert att behålla i en cache. Du kan fråga systemet om denna siffra genom att anropa getMemoryClass()
. Den här metoden returnerar ett heltal som anger antalet megabyte som är tillgängliga för din apps heap.
Växla appar
När användare växlar mellan appar behåller Android appar som inte är i förgrunden – det vill säga som inte är synliga för användaren eller som kör en förgrundstjänst, t.ex. musikuppspelning – i en cache. När en användare först startar en app skapas till exempel en process för den, men när användaren lämnar appen avslutas inte processen. Systemet behåller processen i cacheminnet. Om användaren senare återvänder till appen återanvänder systemet processen, vilket gör att appen växlar snabbare.
Om din app har en process i cacheminnet och den behåller resurser som den för tillfället inte behöver, påverkar din app – även när användaren inte använder den – systemets totala prestanda. När systemet får ont om resurser som t.ex. minne dödar det processer i cacheminnet. Systemet tar också hänsyn till de processer som har mest minne och kan avsluta dem för att frigöra RAM-minne.
Observera: Ju mindre minne din app förbrukar när den ligger i cacheminnet, desto större är chansen att den inte dödas och snabbt kan återupptas. Beroende på de momentana systemkraven är det dock möjligt att cachade processer avslutas när som helst oavsett resursanvändning.
För mer information om hur processer cachas när de inte körs i förgrunden och hur Android bestämmer vilka processer som kan dödas, se guiden Processer och trådar.