WebView è un componente potente che ti consente di visualizzare contenuti web all'interno della tua app per Android. Tuttavia, poiché è essenzialmente un motore del browser completo (Chromium), ha un footprint della memoria significativo e un'architettura multi-processo complessa.
Background tecnico: architettura multi-processo
Sui dispositivi moderni con Android, WebView utilizza un modello multi-processo per migliorare la sicurezza e la stabilità. Quando la tua app utilizza una WebView, la memoria viene distribuita tra diversi processi:
- Processo del browser (il processo dell'app): questo è il processo principale della tua applicazione. Contiene l'oggetto Java
WebViewe la parte "browser" del motore Chromium. Questo processo gestisce l'interfaccia utente, le richieste di rete e il rendering della GPU (integrato direttamente con la pipeline di rendering HWUI di Android). A differenza di Chrome, WebView non ha un processo GPU separato. - Processo di rendering: questo processo è responsabile dell'analisi dell'HTML, dell'esecuzione di JavaScript e del layout. È isolato dal resto del sistema per motivi di sicurezza. Attualmente, le app ottengono un solo processo di rendering per tutte le WebView (tranne in alcuni rari casi speciali), a differenza di Chrome che spesso utilizza processi di rendering separati per siti diversi.

Perché è importante per la memoria
Quando utilizzi dumpsys meminfo <your_package>, vedi solo la memoria utilizzata da
il processo del browser (il processo dell'app). La memoria utilizzata dal processo di rendering viene contabilizzata separatamente.
All'interno del processo del browser, la memoria di WebView viene distribuita come segue:
- Heap Java: contiene il wrapper Java
WebViewe gli oggetti correlati. - Heap nativo: contiene le strutture di dati interne, le cache e lo stato del motore del browser Chromium. Tieni presente che, a causa dell'utilizzo di PartitionAlloc, alcune allocazioni native di WebView potrebbero non essere conteggiate in "Native Heap" in
dumpsys meminfoe potrebbero invece essere visualizzate in "Other" o "Unknown". - Memoria condivisa: utilizzata per la condivisione di buffer grafici e altri dati. Questa potrebbe non essere classificata chiaramente da
dumpsys meminfo.
Strumenti per la risoluzione dei problemi
Chrome DevTools
Lo strumento più potente per analizzare la memoria all'interno di WebView (il processo di rendering) è Chrome DevTools.
Attiva il debug di WebView nella tua app:
// NOTE: In production, this should be gated behind a developer setting // or only enabled for debuggable builds to prevent reverse engineering. WebView.setWebContentsDebuggingEnabled(true);Collega il dispositivo tramite USB.
Apri Chrome sulla macchina host e vai a
chrome://inspect/#devices.Trova la tua app e fai clic su Inspect.
Nella finestra DevTools, vai alla scheda Memory per acquisire snapshot dell'heap o registrare le sequenze temporali di allocazione per l'heap JavaScript.
dumpsys meminfo
Utilizza adb shell dumpsys meminfo --all <package> per visualizzare una suddivisione della memoria.
Cerca la categoria WebView nell'output e i conteggi degli oggetti.
Profilazione del renderer
Poiché il renderer viene eseguito in un processo separato, non puoi profilare il suo heap nativo semplicemente profilando la tua app. Devi identificare in modo specifico il PID del processo di rendering.
Per identificare il PID del renderer corretto quando sono attive più WebView:
Utilizza
dumpsys activity:adb shell dumpsys activity processes <your_package_name>Cerca la sezione
mConnections. Vedrai unConnectionRecordche collega la tua app a unSandboxedProcessService. Il PID di questo processo è il tuo renderer. Esempio:mConnections: - ConnectionRecord{... com.android.memorylab/org.chromium.content.app.SandboxedProcessService0:0 ...}Controlla i nomi dei processi: i processi di rendering in genere hanno il nome
com.google.android.webview:sandboxed_processXo simile. Se una sola app utilizza una WebView, probabilmente ne sarà presente una sola.
Una volta ottenuto il PID, puoi profilarlo utilizzando heapprofd.
Best practice per la memoria di WebView
Distruzione esplicita
Le app devono chiamare WebView.destroy() per indicare quando hanno terminato di utilizzare un'istanza.
Sebbene WebView tenti di garantire che le istanze possano essere sottoposte a Garbage Collection e rilasciare automaticamente tutte le risorse, è difficile garantirlo nel 100% dei casi. Anche quando la Garbage Collection automatica funziona, potrebbe essere ritardata in modo significativo, facendo sì che l'app mantenga le risorse molto più a lungo del previsto.
Se un'app chiama WebView.destroy() al momento opportuno (ad es. in
Activity.onDestroy()), mantenere un riferimento all'oggetto WebView stesso
non comporterà la perdita di risorse native significative. Non è strettamente necessario impostare su null i riferimenti all'oggetto WebView nei campi Activity dopo averlo eliminato, poiché verrà pulito quando l'Activity stessa verrà sottoposta a Garbage Collection.
Esercizi: pratica con la memoria di WebView
Esercizio 1: osservare il footprint multi-processo
Avvia MemoryLab ed esegui una misurazione di base della memoria della tua app:
adb shell dumpsys meminfo com.android.memorylabBase di riferimento di esempio (rango):
TOTAL PSS: 18915 KBTocca Launch WebView (Normal).
In WebView, tocca Allocate JS Memory (1000 DIVs) più volte.
Controlla di nuovo la memoria dell'app:
adb shell dumpsys meminfo com.android.memorylabNota che la memoria nel processo dell'app non aumenta in modo significativo rispetto alla base di riferimento. Questo perché gli elementi DOM si trovano nel processo di rendering.
Trova il processo di rendering:
adb shell ps -A | grep webview | grep sandboxedOutput di esempio:
u0_i9002 14227 1087 1632732 135880 do_epoll_wait 0 S com.google.android.webview:sandboxed_process0Controlla la memoria del processo di rendering (utilizzando il relativo PID):
adb shell dumpsys meminfo 14227Osserva l'elevato PSS TOTALE del processo di rendering. Nella nostra esecuzione di esempio, è aumentato a ~55 MB dopo alcune allocazioni. Tieni presente che le allocazioni JavaScript (gestite dal motore V8) in genere contribuiscono alle sezioni Private Other o Unknown (mmap) di
dumpsys meminfo, anziché all'heap Dalvik.
Esercizio 2: perdita di WebView lato Java
Un errore comune è mantenere un'istanza WebView in un campo statico o in un oggetto di lunga durata che perde. Poiché l'oggetto WebView è un "ancoraggio" pesante che mantiene le risorse native e potenzialmente interi processi di rendering, la sua perdita è molto costosa.

- In MemoryLab, tocca Launch WebView (Java Leak).
- L'attività si chiuderà automaticamente dopo il caricamento della pagina (simulando la navigazione ripetuta e l'accumulo di perdite).
- Tocca il pulsante 4 volte.
Controlla il numero di istanze
WebViewnella tua app:adb shell dumpsys meminfo com.android.memorylabCerca la sezione Objects in basso. Vedrai che il conteggio di
WebViewsè aumentato a 4.Output di esempio (4 istanze perse) su rango:
Objects Views: 51 ViewRootImpl: 5 AppContexts: 14 Activities: 5 Assets: 38 AssetManagers: 0 Local Binders: 55 Proxy Binders: 77 Parcel memory: 41 Parcel count: 68 Death Recipients: 3 WebViews: 4Acquisisci un dump dell'heap e utilizza AHAT per trovare la perdita. Se non hai
ahatnel tuo percorso, puoi crearlo dall'albero Android:# Dump heap from device adb shell am dumpheap com.android.memorylab /data/local/tmp/heap.hprof adb pull /data/local/tmp/heap.hprof # Run ahat using the built JAR (found in out/host/linux-x86/framework/) java -jar out/host/linux-x86/framework/ahat.jar -p 8888 heap.hprofNell'interfaccia web di AHAT (
localhost:8888), fai clic sul link allocations (o sites) nel menu in alto per visualizzare la memoria utilizzata complessiva.
Cerca la classe
android.webkit.WebView. Fai clic sul conteggio delle istanze per visualizzare tutte le istanze attive. Nell'elenco dovresti vedere più istanze.
Fai clic su una delle istanze
WebViewperse. Scorri verso il basso fino alla sezione Sample Path from GC Root. Vedrai che viene mantenuta dall'elencosLeakedWebViewsincom.android.memorylab.WebViewActivity.
← Nativo | ↑ Su | Codice dell'app →