Profiling de rendimiento de Flutter
Cómo diagnosticar problemas de rendimiento de la interfaz de usuario (UI) en Flutter.
Resumen
#El rendimiento de la aplicación abarca varios aspectos, desde la velocidad bruta y el rendimiento de E/S hasta la fluidez de la interfaz de usuario. Aunque esta página se centra principalmente en la fluidez de la UI (ausencia de tirones o jank), las herramientas descritas aquí a menudo también se pueden utilizar para diagnosticar otros problemas de rendimiento.
Flutter ofrece varias herramientas para el análisis del rendimiento. Aquí tienes algunas de ellas:
-
La superposición de rendimiento (Performance Overlay): Muestra un conjunto simplificado de métricas directamente dentro de tu aplicación en ejecución. Para obtener más información, consulta las secciones de este tema.
-
La vista de rendimiento (Performance View): Una interfaz basada en web que se conecta a tu aplicación y muestra métricas de rendimiento detalladas. Forma parte de la herramienta DevTools. Para obtener más información, consulta Usar la vista de rendimiento.
-
Rastreo de rendimiento dentro de Dart: Añade rastreo (tracing) directamente en el código Dart de tu aplicación, utilizando el
paquete dart:developer, y luego realiza el seguimiento del rendimiento de tu aplicación en la herramienta DevTools. Para obtener más información, consulta Rastrear código Dart. -
Benchmarking: Puedes medir y realizar un seguimiento del rendimiento de tu aplicación escribiendo pruebas de benchmark. La biblioteca Flutter Driver proporciona soporte para benchmarking. Utilizando este framework de pruebas de integración, puedes generar métricas que rastrean los tirones (jank), el tamaño de descarga, la eficiencia de la batería y el tiempo de inicio. Para obtener más información, consulta Pruebas de integración.
-
Widget rebuild profiler (IntelliJ para Android Studio): Los tirones (jank) a menudo surgen de reconstrucciones innecesarias de la UI. Si estás utilizando IntelliJ para Android Studio, el Widget Rebuild Profiler te ayuda a identificar y solucionar estos problemas mostrando el número de reconstrucciones de widgets para la pantalla y el fotograma actuales. Para obtener más información, consulta Mostrar datos de rendimiento.
Flutter tiene como objetivo proporcionar un rendimiento de 60 fotogramas por segundo (fps), o 120 fps en dispositivos que lo admitan. Para alcanzar los 60 fps, cada fotograma debe renderizarse aproximadamente cada 16 ms para evitar tirones. Los tirones ocurren cuando los fotogramas tardan significativamente más en renderizarse y se descartan, lo que resulta en un tartamudeo visible en las animaciones. Por ejemplo, si un fotograma tarda ocasionalmente 10 veces más de lo habitual en renderizarse, es probable que se descarte, haciendo que la animación se vea entrecortada.
Conectarse a un dispositivo físico
#Casi toda la depuración de rendimiento de las aplicaciones de Flutter debe realizarse en un dispositivo físico Android o iOS, con tu aplicación de Flutter ejecutándose en modo profile. El uso del modo debug, o la ejecución de aplicaciones en simuladores o emuladores, generalmente no es indicativo del comportamiento final de las compilaciones en modo release. Deberías considerar comprobar el rendimiento en el dispositivo más lento que tus usuarios podrían usar de manera razonable.
Ejecutar en modo profile
#El modo profile de Flutter compila e inicia tu aplicación de manera casi idéntica al modo release, pero con la funcionalidad adicional justa para permitir la depuración de problemas de rendimiento. Por ejemplo, el modo profile proporciona información de rastreo a las herramientas de análisis de rendimiento.
Inicia la aplicación en modo profile de la siguiente manera:
-
En VS Code, abre tu archivo
launch.jsony establece la propiedadflutterModeenprofile(cuando termines el análisis de rendimiento, vuelve a cambiarla areleaseodebug):json"configurations": [ { "name": "Flutter", "request": "launch", "type": "dart", "flutterMode": "profile" } ] -
En Android Studio e IntelliJ, utiliza la opción de menú Run > Flutter Run main.dart in Profile Mode.
-
Desde la línea de comandos, utiliza el flag
--profile:flutter run --profile
Para obtener información sobre los diferentes modos, consulta los modos de compilación de Flutter.
Comenzarás abriendo DevTools y visualizando la superposición de rendimiento, tal como se analiza en la siguiente sección.
Iniciar DevTools
#DevTools proporciona funciones como el profiling, el examen del montículo (heap), la visualización de la cobertura de código, la activación de la superposición de rendimiento y un depurador paso a paso. La vista de la línea de tiempo (Timeline) de DevTools te permite investigar el rendimiento de la UI de tu aplicación fotograma a fotograma.
Una vez que tu aplicación se esté ejecutando en modo profile, inicia DevTools.
Mostrar la superposición de rendimiento
#Puedes alternar la visualización de la superposición de rendimiento de la siguiente manera:
-
Vista de rendimiento (Performance view) de DevTools: La forma más fácil de habilitar el widget PerformanceOverlay es desde la vista de rendimiento (Performance view) en DevTools. Simplemente haz clic en el botón Performance Overlay para alternar la superposición en tu aplicación en ejecución.
-
Línea de comandos: Alterna la superposición de rendimiento utilizando la tecla P desde la línea de comandos.
-
Programáticamente: Para habilitar la superposición de forma programada, consulta la sección Performance overlay (superposición de rendimiento) en la página Depurar aplicaciones de Flutter programáticamente.
Observar la superposición de rendimiento
#La superposición de rendimiento muestra estadísticas en dos gráficos que indican en qué se está invirtiendo el tiempo en tu aplicación. Si la UI presenta tirones (se saltan fotogramas), estos gráficos te ayudan a descubrir por qué. Los gráficos se muestran encima de tu aplicación en ejecución, pero no se dibujan como un widget normal: el propio motor de Flutter pinta la superposición y solo afecta mínimamente al rendimiento. Cada gráfico representa los últimos 300 fotogramas de ese hilo.
Esta sección describe cómo habilitar la superposición de rendimiento y utilizarla para diagnosticar la causa de los tirones en tu aplicación. La siguiente captura de pantalla muestra la superposición de rendimiento ejecutándose en el ejemplo de Flutter Gallery:
Superposición de rendimiento que muestra el hilo de renderizado raster (arriba) y el hilo de la UI (abajo).
Las barras verdes verticales representan el fotograma actual.
Revisar los gráficos
#El gráfico superior (marcado como "GPU") muestra el tiempo empleado por el hilo raster, y el gráfico inferior muestra el tiempo empleado por el hilo de la UI. Las líneas blancas que cruzan los gráficos muestran incrementos de 16 ms a lo largo del eje vertical; si el gráfico supera alguna de estas líneas, significa que estás ejecutando a menos de 60 Hz. El eje horizontal representa los fotogramas. El gráfico solo se actualiza cuando tu aplicación pinta, por lo que si está inactiva, el gráfico deja de moverse.
La superposición siempre debe visualizarse en modo profile, ya que el rendimiento en modo debug se sacrifica intencionadamente a cambio de costosas aserciones destinadas a ayudar al desarrollo, por lo que los resultados pueden ser engañosos.
Cada fotograma debe crearse y mostrarse en una sexagésima de segundo (aproximadamente 16 ms). Un fotograma que supere este límite (en cualquiera de los dos gráficos) no se mostrará correctamente, lo que provocará tirones, y aparecerá una barra vertical roja en uno o ambos gráficos. Si aparece una barra roja en el gráfico de la UI, el código Dart consume demasiados recursos. Si aparece una barra vertical roja en el gráfico de GPU, la escena es demasiado compleja para renderizarse rápidamente.
Las barras rojas verticales indican que el fotograma actual es costoso tanto de renderizar como de pintar.
Cuando ambos gráficos muestran barras rojas, comienza diagnosticando el hilo de la UI.
Revisar los hilos
#Flutter utiliza varios hilos para realizar su trabajo, aunque solo dos de ellos se muestran en la superposición. Todo tu código Dart se ejecuta en el hilo de la UI. Aunque no tienes acceso directo a ningún otro hilo, tus acciones en el hilo de la UI tienen consecuencias en el rendimiento de los demás hilos.
- Hilo de la plataforma
-
El hilo principal de la plataforma. El código del plugin se ejecuta aquí. Para obtener más información, consulta la documentación de UIKit para iOS o la documentación de MainThread para Android. Este hilo no se muestra en la superposición de rendimiento.
- Hilo de la UI
-
El hilo de la UI ejecuta código Dart en la máquina virtual (VM) de Dart. Este hilo incluye el código que escribiste y el código ejecutado por el framework de Flutter en nombre de tu aplicación. Cuando tu aplicación crea y muestra una escena, el hilo de la UI crea un árbol de capas (layer tree), un objeto ligero que contiene comandos de dibujo independientes del dispositivo, y envía dicho árbol al hilo raster para que sea renderizado en el dispositivo. ¡No bloquees este hilo! Se muestra en la fila inferior de la superposición de rendimiento.
- Hilo raster
-
El hilo raster toma el árbol de capas y lo muestra comunicándose con la GPU (unidad de procesamiento gráfico). No puedes acceder directamente al hilo raster ni a sus datos pero, si este hilo es lento, es a consecuencia de algo que hiciste en el código Dart. Las bibliotecas gráficas Skia e Impeller se ejecutan en este hilo. Se muestra en la fila superior de la superposición de rendimiento. Ten en cuenta que, aunque el hilo raster rasteriza para la GPU, el hilo en sí se ejecuta en la CPU.
- Hilo de E/S
-
Realiza tareas costosas (principalmente de E/S) que de otro modo bloquearían el hilo de la UI o el hilo raster. Este hilo no se muestra en la superposición de rendimiento.
Para obtener enlaces con más información y videos, consulta La arquitectura del Framework en la wiki de Flutter, y el artículo de la comunidad, The Layer Cake.
Identificar problemas
#Revisar el gráfico de UI
#Si la superposición de rendimiento muestra color rojo en el gráfico de la UI, comienza por analizar el rendimiento de la VM de Dart, incluso si el gráfico de GPU también se muestra en rojo.
Revisar el gráfico de GPU
#A veces, una escena da como resultado un árbol de capas fácil de construir, pero costoso de renderizar en el hilo raster. Cuando esto sucede, el gráfico de la UI no muestra rojo, pero el gráfico de GPU sí. En este caso, tendrás que averiguar qué está haciendo tu código para que el código de renderizado sea lento. Ciertos tipos de cargas de trabajo son más difíciles para la GPU. Pueden implicar llamadas innecesarias a saveLayer, superposición de opacidades con múltiples objetos y recortes o sombras en situaciones específicas.
Si sospechas que el origen de la lentitud ocurre durante una animación, haz clic en el botón Slow Animations en el inspector de Flutter para ralentizar las animaciones 5 veces. Si deseas tener más control sobre la velocidad, también puedes hacerlo de forma programada.
¿La lentitud está en el primer fotograma o en toda la animación? Si es en toda la animación, ¿el recorte (clipping) está causando la ralentización? Quizás haya una forma alternativa de dibujar la escena que no utilice recortes. Por ejemplo, superponer esquinas opacas sobre un cuadrado en lugar de recortar a un rectángulo redondeado. Si se trata de una escena estática que se está desvaneciendo, rotando o manipulando de alguna otra manera, un RepaintBoundary podría ayudar.
Comprobación de capas fuera de pantalla
#El método saveLayer es uno de los métodos más costosos en el framework de Flutter. Es útil al aplicar un posprocesamiento a la escena, pero puede ralentizar tu aplicación y debe evitarse si no lo necesitas. Incluso si no llamas a saveLayer explícitamente, podrían ocurrir llamadas implícitas en tu nombre, por ejemplo, al especificar Clip.antiAliasWithSaveLayer (normalmente como un clipBehavior).
Por ejemplo, tal vez tengas un grupo de objetos con opacidades que se renderizan utilizando saveLayer. En este caso, probablemente sea más eficiente aplicar una opacidad a cada widget Java/Dart individual, en lugar de a un widget padre más arriba en el árbol de widgets. Lo mismo se aplica a otras operaciones potencialmente costosas, como los recortes (clipping) o las sombras.
Cuando encuentres llamadas a saveLayer, hazte estas preguntas:
- ¿Necesita la aplicación este efecto?
- ¿Se puede eliminar alguna de estas llamadas?
- ¿Puedo aplicar el mismo efecto a un elemento individual en lugar de a un grupo?
Comprobación de imágenes no almacenadas en caché
#Almacenar en caché una imagen con RepaintBoundary es bueno, cuando tiene sentido.
Una de las operaciones más costosas, desde la perspectiva de los recursos, es renderizar una textura utilizando un archivo de imagen. Primero, la imagen comprimida se recupera del almacenamiento persistente. La imagen se descomprime en la memoria del host (memoria de la GPU) y se transfiere a la memoria del dispositivo (RAM).
En otras palabras, las operaciones de E/S de imágenes pueden ser costosas. La caché proporciona instantáneas de jerarquías complejas para que sean más fáciles de renderizar en los fotogramas siguientes. Dado que las entradas de la caché raster son costosas de construir y ocupan mucha memoria de la GPU, almacena imágenes en caché únicamente cuando sea absolutamente necesario.
Otros recursos
#Los siguientes recursos proporcionan más información sobre el uso de las herramientas de Flutter y la depuración en Flutter:
- Depuración
- Vista de rendimiento (Performance)
- Flutter Inspector
- Charla sobre el inspector de Flutter, presentada en la DartConf 2018
- Por qué Flutter utiliza Dart, un artículo en Hackernoon
- Por qué Flutter utiliza Dart, un video en el canal de Flutter
- DevTools: herramientas de rendimiento para aplicaciones de Dart y Flutter
- Documentación de la API de Flutter, especialmente la clase
PerformanceOverlayy el paquetedart:developer
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-11. Ver código fuente oreportar un problema.