WebView es un componente potente que te permite mostrar contenido web en tu aplicación para Android. Sin embargo, debido a que es esencialmente un motor de navegador con todas las funciones (Chromium), tiene un espacio en memoria significativo y una arquitectura compleja de varios procesos.
Información técnica: Arquitectura de varios procesos
En los dispositivos modernos con tecnología Android, WebView usa un modelo de varios procesos para mejorar la seguridad y la estabilidad. Cuando tu app usa un WebView, la memoria se distribuye en diferentes procesos:
- Proceso del navegador (el proceso de la app): Es el proceso principal de tu aplicación. Contiene el objeto
WebViewde Java y la parte del "navegador" del motor de Chromium. Este proceso administra la IU, las solicitudes de red y la renderización de la GPU (integrada directamente con la canalización de renderización de HWUI de Android). A diferencia de Chrome, WebView no tiene un proceso de GPU independiente. - Proceso de renderizador: Este proceso es responsable de analizar HTML, ejecutar JavaScript y el diseño. Está aislado del resto del sistema por motivos de seguridad. Actualmente, las apps solo obtienen un proceso de renderizador para todos los WebViews (excepto en algunos casos especiales poco frecuentes), a diferencia de Chrome, que suele usar procesos de renderizador independientes para diferentes sitios.

Por qué es importante para la memoria
Cuando usas dumpsys meminfo <your_package>, solo ves la memoria que usa
el proceso del navegador (el proceso de tu app). La memoria que usa el proceso del renderizador se contabiliza por separado.
Dentro del proceso del navegador, la memoria de WebView se distribuye de la siguiente manera:
- Montón de Java: Contiene el wrapper de
WebViewde Java y los objetos relacionados. - Montón nativo: Contiene las estructuras de datos internas, las memorias caché y el estado del motor del navegador Chromium. Ten en cuenta que, debido al uso de PartitionAlloc, es posible que algunas asignaciones nativas de WebView no se cuenten en "Native Heap" en
dumpsys meminfoy, en su lugar, aparezcan en "Other" o "Unknown". - Memoria compartida: Se usa para compartir búferes gráficos y otros datos. Es posible que
dumpsys meminfono la clasifique claramente.
Herramientas de solución de problemas
Herramientas para desarrolladores de Chrome
La herramienta más potente para analizar la memoria dentro de WebView (el proceso de renderizador) son las Herramientas para desarrolladores de Chrome.
Habilita la depuración de WebView en tu 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);Conecta el dispositivo con un cable USB.
Abre Chrome en tu máquina anfitrión y navega a
chrome://inspect/#devices.Busca tu app y haz clic en inspect.
En la ventana de Herramientas para desarrolladores, ve a la pestaña Memory para tomar instantáneas del montón o registrar líneas de tiempo de asignación para el montón de JavaScript.
dumpsys meminfo
Usa adb shell dumpsys meminfo --all <package> para ver un desglose de la memoria.
Busca la categoría WebView en el resultado y los recuentos de objetos.
Genera el perfil del renderizador
Dado que el renderizador se ejecuta en un proceso independiente, no puedes generar el perfil de su montón nativo solo generando el perfil de tu app. Debes identificar el PID del proceso de renderizador de forma específica.
Para identificar el PID del renderizador correcto cuando hay varios WebViews activos, haz lo siguiente:
Usa
dumpsys activity:adb shell dumpsys activity processes <your_package_name>Busca la sección
mConnections. Verás unConnectionRecordque vincula tu app a unSandboxedProcessService. El PID de ese proceso es tu renderizador. Ejemplo:mConnections: - ConnectionRecord{... com.android.memorylab/org.chromium.content.app.SandboxedProcessService0:0 ...}Verifica los nombres de los procesos: Los procesos de renderizador suelen llamarse
com.google.android.webview:sandboxed_processXo similar. Si solo una app usa un WebView, es probable que solo haya uno.
Una vez que tengas el PID, puedes generar su perfil con heapprofd.
Prácticas recomendadas para la memoria de WebView
Destrucción explícita
Se espera que las apps llamen a WebView.destroy() para indicar cuándo terminaron con una instancia.
Si bien WebView intenta garantizar que las instancias se puedan recolectar como elementos no utilizados y liberar todos sus recursos automáticamente, es difícil garantizar esto en el 100% de los casos. Incluso cuando funciona la recolección automática de elementos no utilizados, puede demorarse significativamente, lo que hace que la app conserve los recursos mucho más tiempo de lo esperado.
Si una app llama a WebView.destroy() en el momento adecuado (p.ej., en
Activity.onDestroy()), conservar una referencia al objeto WebView en sí
no filtrará ningún recurso nativo significativo. No es estrictamente necesario anular las referencias al objeto WebView en los campos de actividad después de destruirlo, ya que se limpiará cuando la actividad en sí se recolecte como elemento no utilizado.
Ejercicios: Experiencia práctica con la memoria de WebView
Ejercicio 1: Observa la huella de varios procesos
Inicia MemoryLab y toma una medición de referencia de la memoria de tu app:
adb shell dumpsys meminfo com.android.memorylabReferencia de muestra (rango):
TOTAL PSS: 18915 KBPresiona Launch WebView (Normal).
En WebView, presiona Allocate JS Memory (1000 DIVs) varias veces.
Vuelve a verificar la memoria de la app:
adb shell dumpsys meminfo com.android.memorylabObserva que la memoria en el proceso de tu app no aumenta significativamente en comparación con la referencia. Esto se debe a que los elementos DOM están en el proceso de renderizador.
Busca el proceso de renderizador:
adb shell ps -A | grep webview | grep sandboxedResultado de ejemplo:
u0_i9002 14227 1087 1632732 135880 do_epoll_wait 0 S com.google.android.webview:sandboxed_process0Verifica la memoria del proceso de renderizador (con su PID):
adb shell dumpsys meminfo 14227Observa el PSS TOTAL alto del proceso de renderizador. En nuestra ejecución de muestra, saltó a ~55 MB después de algunas asignaciones. Ten en cuenta que las asignaciones de JavaScript (que controla el motor V8) suelen contribuir a las secciones Private Other o Unknown (mmap) de
dumpsys meminfo, en lugar del montón de Dalvik.
Ejercicio 2: La fuga de WebView del lado de Java
Un error común es conservar una instancia de WebView en un campo estático o en un objeto de larga duración que se filtra. Debido a que el objeto WebView es un "ancla" pesada que conserva recursos nativos y, potencialmente, procesos de renderizador completos, filtrarlo es muy costoso.

- En MemoryLab, presiona Launch WebView (Java Leak).
- La actividad se cerrará automáticamente después de que se cargue la página (simulando la navegación repetida y la acumulación de fugas).
- Presiona el botón 4 veces.
Verifica la cantidad de instancias de
WebViewen tu app:adb shell dumpsys meminfo com.android.memorylabBusca la sección Objects en la parte inferior. Verás que el recuento de
WebViewsaumentó a 4.Resultado de muestra (4 instancias filtradas) en 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: 4Captura un volcado de montón y usa AHAT para encontrar la fuga. Si no tienes
ahaten tu ruta de acceso, puedes compilarlo desde el árbol de 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.hprofEn la interfaz web de AHAT (
localhost:8888), haz clic en el vínculo allocations (o sites) en el menú superior para ver el uso de memoria general.
Busca la clase
android.webkit.WebView. Haz clic en su recuento de instancias para ver todas las instancias activas. Deberías ver varias instancias en la lista.
Haz clic en una de las instancias de
WebViewfiltradas. Desplázate hacia abajo hasta la sección Sample Path from GC Root. Verás que la mantiene la listasLeakedWebViewsencom.android.memorylab.WebViewActivity.
← Nativo | ↑ Arriba | Código de la app →