Los profilers de Android Studio: cuatro instrumentos, cuatro preguntas
Android Studio no tiene un perfilador sino una familia de instrumentos que responden preguntas distintas y que se estorban entre sí cuando se usan a la vez. Esta lección ordena el arsenal por la pregunta que contesta cada uno: el de CPU y sus cuatro modos de mirar el tiempo, el de memoria en sus dos naturalezas, el inspector de red que dejó de ser un profiler, y la medición de energía que hoy depende del hardware del dispositivo. El eje transversal es la fidelidad de la medida: qué distorsiona cada instrumento, por qué una compilación depurable miente y qué significa realmente compilar la aplicación como perfilable.
Hay una manera muy eficaz de perder una tarde entera: abrir el perfilador con la esperanza de que algo salte a la vista. No saltará. Un perfilador no descubre problemas, responde preguntas, y cada uno de los instrumentos que Android Studio agrupa bajo ese nombre responde una pregunta diferente y solo una. El de CPU contesta dónde se consume el tiempo; el de memoria, qué ocupa el montón y quién impide liberarlo; el inspector de red, qué se pide y cuánto tarda en volver; el de energía, qué componente físico del dispositivo está despierto. Elegir mal el instrumento no produce un resultado erróneo sino algo peor: produce un resultado plausible que apunta al sitio equivocado. Y por debajo de todos ellos hay un problema común que la mayoría ignora: el acto de medir altera lo medido, y una aplicación compilada para ser depurada se comporta de una forma que jamás verá ningún usuario.
- Asociar cada instrumento a la pregunta concreta que contesta y descartar los que no la contestan.
- Distinguir los cuatro modos de captura de CPU y el compromiso entre fidelidad y sobrecarga de cada uno.
- Entender por qué una compilación depurable distorsiona la medida y qué aporta declarar la aplicación perfilable.
- Encadenar los instrumentos en una metodología: primero delimitar el síntoma, después ampliar sobre la sospecha.
Cuatro instrumentos, cuatro preguntas
La ventana de perfilado moderna abandonó los cuatro carriles simultáneos que había antes y se reorganizó en torno a tareas: se elige el proceso, se elige la pregunta y la herramienta configura la captura adecuada. El cambio no es cosmético. Los carriles simultáneos invitaban a mirarlo todo a la vez, que es exactamente la postura que impide encontrar nada, mientras que la tarea obliga a declarar qué se busca antes de empezar a buscarlo.
CPU: dónde se va el tiempo
Responde qué código se ejecuta y durante cuánto. Es el instrumento del trabón, del arranque lento y del cálculo que no acaba. Tiene cuatro modos de captura y elegir mal es el error más caro del nivel.
Memoria: qué ocupa y qué retiene
Dos naturalezas distintas bajo un mismo nombre: el volcado del montón, que es una fotografía de lo que hay ahora, y el registro de asignaciones, que es la película de lo que se creó y se destruyó.
Red: qué se pide y qué vuelve
Dejó de ser un perfilador y vive en la ventana de inspección de la aplicación. Muestra cada petición con sus cabeceras, su cuerpo y su cronología, incluida la fase de conexión que casi nadie mide.
Energía: qué está despierto
El instrumento más dependiente del hardware. La medición real de consumo exige un dispositivo con monitor de potencia integrado; en el resto solo hay una estimación a partir de contadores del sistema.
La disciplina consiste en no abrir ninguno hasta poder escribir el síntoma en una frase que contenga un sujeto y una magnitud. «La aplicación va lenta» no es un síntoma; «la lista se traba al desplazarla rápido en un dispositivo de gama baja» sí lo es, y esa frase ya contiene la elección del instrumento.
Los cuatro modos de mirar el tiempo
El perfilador de CPU no es uno. Bajo esa etiqueta conviven cuatro mecanismos con teorías de medición incompatibles, y confundirlos produce conclusiones invertidas.
El registro instrumentado de métodos reescribe el código para que cada entrada y cada salida de método se anoten. Da recuentos de llamadas exactos y no se le escapa ningún método, por corto que sea. A cambio, la sobrecarga es brutal —multiplica por varias veces el tiempo de ejecución— y, lo que es peor, esa sobrecarga es proporcional al número de llamadas, de modo que penaliza especialmente a los métodos pequeños llamados muchas veces. Un perfil instrumentado convierte a una función trivial invocada un millón de veces en la protagonista falsa de un informe.
El muestreo de métodos interrumpe periódicamente el hilo y anota su pila. La sobrecarga es baja y estable, y el resultado es estadísticamente honesto respecto al tiempo, pero pierde por completo los métodos que nunca están vivos en el instante del muestreo. Es el modo correcto para la pregunta «dónde se va el tiempo» y el modo equivocado para «cuántas veces se llama a esto».
El muestreo de pilas nativas hace lo mismo apoyándose en el muestreador del sistema, de manera que ve la pila completa: código gestionado, código nativo y bibliotecas del sistema. Es el único que revela que el tiempo se está yendo dentro de una biblioteca de imágenes escrita en C o en la propia máquina virtual.
La traza del sistema cambia de objeto: ya no observa tu proceso sino la máquina entera, con la planificación de hilos, la frecuencia de los núcleos y los eventos de dibujo. Contesta preguntas que ningún perfilador de proceso puede contestar, y es la que abre la lección siguiente.
Los dos primeros modos no dependen de la interfaz gráfica, lo que resulta decisivo cuando el dispositivo problemático está en manos de otra persona o cuando la captura debe automatizarse dentro de un guion de integración continua.
# Muestreo de metodos disparado desde la consola, sin abrir el entorno.
adb shell am profile start --sampling 1000 com.ejemplo.app \
/data/local/tmp/perfil.trace
# ... reproducir el sintoma ...
adb shell am profile stop com.ejemplo.app
adb pull /data/local/tmp/perfil.trace .
Cuando la aplicación es depurable, el entorno de ejecución desactiva optimizaciones, mantiene información adicional viva y permite que el depurador se enganche en cualquier momento. Los números que salen de ahí no son los de tu usuario: pueden ser dos o tres veces peores, y no de manera uniforme, así que ni siquiera sirven para comparar dos versiones entre sí con confianza. La alternativa es declarar la aplicación como perfilable en el manifiesto, lo que permite capturar trazas de sistema y muestreos de pila sobre una compilación de publicación real, con las optimizaciones aplicadas y el ofuscador ya pasado. Se pierde el registro de asignaciones y el volcado de montón, que exigen depurabilidad, pero se gana lo único que importa cuando se habla de rendimiento: que el sujeto medido sea el artefacto que se publica.
Memoria, red y energía: el alcance real de cada uno
El instrumento de memoria tiene dos caras que responden preguntas opuestas. El volcado del montón es una fotografía instantánea: dice qué objetos existen ahora, cuánto ocupan por sí mismos y cuánto mantienen vivo a través de sus referencias. Es el instrumento de la fuga y del exceso de ocupación. El registro de asignaciones es lo contrario, una película: dice qué se creó durante un intervalo, en qué línea y con qué frecuencia, y es el instrumento de la presión sobre el recolector, ese problema que no aparece como falta de memoria sino como microtrabones periódicos mientras el recolector trabaja. La tercera cara, el consumo nativo, escapa a ambos: desde que los mapas de bits viven fuera del montón gestionado, una aplicación puede morir por memoria sin que el volcado muestre nada anormal.
Volcado del montón
Qué existe ahora y cuánto retiene cada objeto. Es el instrumento de la fuga y del exceso de ocupación, y no dice absolutamente nada del pasado.
Registro de asignaciones
Qué se creó durante un intervalo, en qué línea y con qué frecuencia. Es el instrumento de la presión sobre el recolector, y no dice nada de lo que sobrevive.
Consumo nativo
Lo que vive fuera del montón gestionado. Desde que los mapas de bits se alojan ahí, una aplicación puede morir por memoria con un volcado impecable.
La gráfica de totales
Antes de cualquier volcado, la forma de la curva ya clasifica el problema: dientes de sierra sanos, escalón permanente o crecimiento monótono sin retorno.
El antiguo perfilador de red fue retirado y su función vive hoy en el inspector de red, dentro de la ventana de inspección de aplicaciones. La razón del traslado es conceptual: la red no es un recurso de la máquina como la CPU o la memoria, sino un diálogo con un tercero, y lo que se necesita es leer ese diálogo. El inspector muestra cada petición con su método, su tamaño, sus cabeceras y su cronología desglosada, y esa cronología es el dato que suele cambiar el diagnóstico: descubrir que el tiempo se va en el establecimiento de la conexión y no en la respuesta del servidor lleva a arreglar la reutilización de conexiones y no a optimizar la base de datos ajena.
La energía es el caso donde la honestidad de la herramienta se nota más. Medir consumo eléctrico real requiere un monitor de potencia en el propio dispositivo, y solo lo llevan algunos modelos recientes; en los demás, cualquier cifra es una estimación derivada de cuánto tiempo estuvo despierto cada componente. Por eso la pregunta útil casi nunca es cuántos milivatios, sino qué mantiene despierto qué: una alarma que despierta el procesador cada minuto, una adquisición de bloqueo que no se libera, una petición de ubicación de alta precisión que sigue viva en segundo plano.
flowchart TD
A[Sintoma descrito en una frase] --> B{Que magnitud se degrada}
B -->|Se traba o tarda en arrancar| C[Traza del sistema]
B -->|Un calculo concreto es lento| D[Muestreo de metodos o de pilas nativas]
B -->|La memoria crece y no baja| E[Volcado del monton]
B -->|Microtrabones periodicos| F[Registro de asignaciones]
B -->|La pantalla espera datos| G[Inspector de red]
B -->|La bateria se agota| H[Contadores de energia y despertares]
C --> I[Medir sobre compilacion perfilable]
D --> I
style A fill:#f38ba8,color:#11111b
style I fill:#a6e3a1,color:#11111bLa secuencia que funciona es siempre la misma y va de lo general a lo particular. Se empieza con la traza del sistema, que tiene sobrecarga mínima y ve la máquina entera, para localizar cuándo ocurre el problema y qué hilo lo sufre. Solo cuando ese intervalo está acotado se amplía con un muestreo de métodos sobre esos pocos segundos, que ya sí dirá qué código concreto ocupa el hilo. Hacerlo al revés —empezar por el registro instrumentado sobre toda la sesión— produce un archivo enorme, una interfaz que se arrastra y una lista de métodos ordenada por un tiempo que la propia instrumentación ha inflado.
Detrás de la elección aparentemente trivial entre instrumentar y muestrear hay una diferencia epistemológica que conviene ver con claridad, porque explica por qué dos perfiladores del mismo programa producen informes que se contradicen sin que ninguno mienta. Instrumentar es un método censal: se anota cada entrada y cada salida, de modo que el recuento de llamadas es exacto y ningún método, por breve que sea, escapa al registro. Muestrear es un método demoscópico: se interrumpe el hilo cada cierto tiempo y se anota qué estaba haciendo, de modo que lo que se obtiene no es una lista de hechos sino una distribución de probabilidad sobre el tiempo. El censo es exacto en el recuento pero destruye el objeto que mide, porque el coste de anotar cada llamada se suma al coste de la llamada y ese coste no se reparte de forma neutral: penaliza en proporción a la frecuencia, es decir, castiga precisamente a las funciones pequeñas y muy invocadas que suelen ser las más optimizadas del programa. La encuesta apenas perturba el objeto, pero solo puede hablar de lo que dura lo bastante como para ser sorprendido despierto, y por tanto es estructuralmente ciega a lo breve por muy frecuente que sea. De ahí que la pregunta correcta antes de abrir un perfilador no sea cuál es más preciso, sino qué clase de afirmación se pretende sostener: si es «esta función se llama muchísimas más veces de las que debería», el censo es el instrumento y su distorsión temporal resulta irrelevante; si es «el tiempo de esta pantalla se va aquí», la encuesta es el instrumento y su ceguera a lo breve resulta irrelevante. Este razonamiento se extiende a todos los demás instrumentos del capítulo, porque todos comparten la misma estructura: un volcado de montón es un censo instantáneo que no dice nada del pasado, un registro de asignaciones es una película que no dice nada de lo que sobrevive, una traza de sistema es una encuesta sobre la máquina entera que ignora el interior de tu proceso. Ninguno es la verdad; cada uno es una proyección deliberada que sacrifica un eje para poder ver otro con nitidez. Perfilar con criterio es, en el fondo, elegir conscientemente qué se está dispuesto a no ver.
- Escribe tres síntomas de tu aplicación con sujeto y magnitud, y asigna a cada uno el instrumento que lo contesta y los que quedan descartados. Justifica cada descarte.
- Perfila la misma pantalla con registro instrumentado y con muestreo de métodos, y compara el orden de la lista de métodos. Explica qué función sube en el informe instrumentado y por qué.
- Declara la aplicación como perfilable, captura una traza del sistema sobre la compilación de publicación y compara la duración de una operación con la que mide la compilación depurable.
- Provoca presión sobre el recolector creando objetos efímeros dentro del desplazamiento de una lista; localiza el punto exacto con el registro de asignaciones y comprueba que el volcado del montón no lo revela.
- Abre el inspector de red sobre una pantalla que carga datos y desglosa la cronología de una petición. Determina qué fracción del tiempo es conexión y qué fracción es respuesta.