Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
La generación de perfiles de rendimiento es el proceso de medir el rendimiento de una aplicación para identificar áreas de mejora. Las aplicaciones cliente y MAUI de .NET, en general, están interesadas en:
- Tiempo de inicio: el tiempo que tarda la aplicación en iniciarse y mostrar la primera pantalla.
- Uso de CPU: si los métodos específicos consumen demasiado tiempo de CPU: a través de muchas llamadas o operaciones de larga duración.
- Uso de memoria: si se realizan muchas asignaciones más allá del motivo o si hay pérdidas de memoria.
Las técnicas y herramientas para mejorar estas métricas son diferentes, que tenemos previsto desmitificar en esta guía. Las herramientas que se usan para generar perfiles de aplicaciones MAUI de .NET también pueden variar en función de la plataforma. En esta guía se tratan los enfoques de generación de perfiles de Android, iOS, Mac Catalyst y Windows.
Importante
Generar siempre las compilaciones de perfiles Release para mediciones de rendimiento precisas.
Debug Las compilaciones utilizan el intérprete (UseInterpreter=true) para el soporte de recarga de código en caliente de C#, lo que afecta significativamente al rendimiento y genera resultados poco realistas.
Prerrequisitos
Instalación de herramientas de diagnóstico
Para generar perfiles de aplicaciones .NET MAUI en iOS y Android, debe instalar las siguientes herramientas globales de .NET:
-
dotnet-trace- Recopila seguimientos de CPU y datos de rendimiento -
dotnet-dsrouter- Reenvía las conexiones de diagnóstico desde dispositivos remotos a la máquina local. -
dotnet-gcdump- Recopila volcados de memoria para analizar el uso de memoria administrada.
Puede instalar estas herramientas mediante los siguientes comandos:
$ dotnet tool install -g dotnet-trace
You can invoke the tool using the following command: dotnet-trace
Tool 'dotnet-trace' was successfully installed.
$ dotnet tool install -g dotnet-dsrouter
You can invoke the tool using the following command: dotnet-dsrouter
Tool 'dotnet-dsrouter' was successfully installed.
$ dotnet tool install -g dotnet-gcdump
You can invoke the tool using the following command: dotnet-gcdump
Tool 'dotnet-gcdump' was successfully installed.
Nota:
Necesita al menos la versión 9.0.652701 de todas las herramientas de diagnóstico para usar las características descritas en esta guía. Compruebe dotnet-trace, dotnet-dsrouter y dotnet-gcdump en NuGet para ver las versiones más recientes.
A partir de la versión 9.0.652701, tanto dotnet-trace como dotnet-gcdump incluyen la opción --dsrouter que inicia y administra automáticamente dotnet-dsrouter como un subproceso. Esto elimina la necesidad de ejecutarse dotnet-dsrouter por separado, lo que simplifica significativamente el flujo de trabajo de generación de perfiles.
Consulte la sesión de la .NET Conf, Herramientas de diagnóstico de .NET con IA, para una demostración en vivo del uso de estas herramientas.
Cómo funcionan conjuntamente las herramientas
Para usar estas herramientas de diagnóstico en iOS y Android, varios componentes funcionan juntos:
- Las herramientas globales de .NET (
dotnet-trace,dotnet-gcdump,dotnet-dsrouter) se ejecutan en la máquina de desarrollo. - El componente de diagnóstico Mono (
libmono-component-diagnostics_tracing.so) se incluye en el paquete de la aplicación. -
dotnet-dsrouterreenvía la conexión de diagnóstico desde el dispositivo remoto o emulador a un puerto local en el equipo. - Las herramientas de diagnóstico se conectan a este puerto local para recopilar datos de perfilado
La opción --dsrouter en dotnet-trace y dotnet-gcdump maneja automáticamente la complejidad de iniciar dotnet-dsrouter y coordinar la conexión.
Compilación de la aplicación para la generación de perfiles
Para habilitar la generación de perfiles, la aplicación debe compilarse con propiedades especiales de MSBuild que incluyan los componentes de diagnóstico y configuren la conexión a las herramientas de generación de perfiles.
Comprensión de las propiedades de diagnóstico
Las siguientes propiedades de MSBuild controlan cómo se comunica la aplicación con las herramientas de diagnóstico:
DiagnosticAddress: la dirección IP dondedotnet-dsrouterestá escuchando. Utiliza10.0.2.2para emuladores de Android (es la dirección de retorno de la máquina host desde el emulador) y127.0.0.1para dispositivos físicos e iOS.DiagnosticPort: número de puerto de la conexión de diagnóstico (el valor predeterminado es9000).DiagnosticSuspend: cuandotrue, la aplicación espera a que el generador de perfiles se conecte antes de iniciarse. Cuandofalse, la aplicación se inicia inmediatamente y el generador de perfiles puede conectarse más adelante. Se usatruepara la generación de perfiles de inicio,falsepara la generación de perfiles en tiempo de ejecución y los volcados de memoria.DiagnosticListenMode: Establecer enconnectpara Android (la aplicación se conecta adotnet-dsrouter), o enlistenpara iOS (la aplicación escucha adotnet-dsrouterpara conectarse a ella).EnableDiagnostics: cuandotrue, incluye el componente de diagnóstico Mono en el paquete de la aplicación. Esto se establece implícitamente al establecer cualquiera de lasDiagnostic*propiedades de MSBuild. Esta propiedad funciona en Android, iOS y Mac Catalyst.
Nota:
Cuando se usa CoreCLR (actualmente experimental en Android, con compatibilidad con iOS planeada), el componente de diagnóstico se integra en el entorno de ejecución y EnableDiagnostics no es necesario.
Ejemplos de comandos de compilación
Al ejecutar dotnet-trace o dotnet-gcdump con la --dsrouter opción , la herramienta muestra instrucciones para compilar la aplicación.
Por ejemplo:
Para emuladores de Android:
dotnet build -t:Run -c Release -f net10.0-android -p:DiagnosticAddress=10.0.2.2 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=false -p:DiagnosticListenMode=connect
Para dispositivos Android:
dotnet build -t:Run -c Release -f net10.0-android -p:DiagnosticAddress=127.0.0.1 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=false -p:DiagnosticListenMode=connect
Para dispositivos y simuladores de iOS:
dotnet build -t:Run -c Release -f net10.0-ios -p:DiagnosticAddress=127.0.0.1 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=false -p:DiagnosticListenMode=listen
Nota:
Use -f net10.0-android o -f net10.0-ios para proyectos con varias plataformas de destino en $(TargetFrameworks).
Importante
Las aplicaciones compiladas con estas propiedades de diagnóstico solo deben usarse para el desarrollo y las pruebas. Nunca publique compilaciones con componentes de diagnóstico habilitados en producción, ya que pueden exponer endpoints con información más detallada sobre el código de la aplicación.
Generación de perfiles de uso de CPU
La dotnet-trace herramienta recopila información de muestreo de CPU en formatos como .nettrace y .speedscope.json. Estas trazas muestran el tiempo invertido en cada método, lo que le ayuda a identificar los cuellos de botella de rendimiento en su aplicación.
El flujo de trabajo para la generación de perfiles de CPU depende de si estás midiendo el tiempo de inicio o generando perfiles de las operaciones en tiempo de ejecución. La diferencia clave es la -p:DiagnosticSuspend propiedad de MSBuild.
Tiempo de inicio de generación de perfiles
Para capturar medidas precisas de tiempo de inicio, suspenda el inicio de la aplicación hasta que el generador de perfiles esté listo. Esto garantiza que captures toda la secuencia de inicio desde el comienzo.
En un terminal, inicie
dotnet-tracecon la opción--dsrouter.dotnet-trace collect --dsrouter android-emu --format speedscopeO para un dispositivo Android físico:
dotnet-trace collect --dsrouter android --format speedscopeEn el caso de los dispositivos y simuladores de iOS, use
--dsrouter ioso--dsrouter ios-simrespectivamente.En otro terminal, compile e implemente la aplicación con
-p:DiagnosticSuspend=truepara pausar en el inicio:Para emuladores de Android:
dotnet build -t:Run -c Release -f net10.0-android -p:DiagnosticAddress=10.0.2.2 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=true -p:DiagnosticListenMode=connectPara dispositivos Android:
dotnet build -t:Run -c Release -f net10.0-android -p:DiagnosticAddress=127.0.0.1 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=true -p:DiagnosticListenMode=connectPara iOS (dispositivos y simuladores):
dotnet build -t:Run -c Release -f net10.0-ios -p:DiagnosticAddress=127.0.0.1 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=true -p:DiagnosticListenMode=listenLa aplicación se pausará en la pantalla de presentación, esperando a que
dotnet-tracese conecte. Una vez conectado, la aplicación se iniciará ydotnet-tracecomenzará a grabar.Permitir que la aplicación se inicie completamente y llegue a la pantalla inicial.
Presione
<Enter>en el terminal para detener ladotnet-tracegrabación.
El archivo de seguimiento se guardará en el directorio actual. Use la -o opción para especificar un directorio de salida diferente.
Generación de perfiles de operaciones en tiempo de ejecución
Para generar perfiles de operaciones específicas durante el tiempo de ejecución (como pulsaciones de botón, navegación o desplazamiento), use -p:DiagnosticSuspend=false y conecte el generador de perfiles una vez iniciada la aplicación.
Compile e implemente la aplicación con
-p:DiagnosticSuspend=false:dotnet build -t:Run -c Release -f net10.0-android -p:DiagnosticAddress=127.0.0.1 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=false -p:DiagnosticListenMode=connectDirígete a la parte de la aplicación que deseas analizar.
Inicie
dotnet-tracecon la--dsrouteropción:dotnet-trace collect --dsrouter android --format speedscopeRealice la operación que desea perfilar.
Presione
<Enter>para detener el seguimiento.
Este enfoque genera un archivo de seguimiento más centrado que contiene solo la operación específica que está investigando.
Comprensión de la salida del seguimiento
Cuando dotnet-trace está recopilando un seguimiento, verá una salida similar a:
Process : $HOME/.dotnet/tools/dotnet-dsrouter
Output File : /tmp/hellomaui-app-trace
[00:00:00:35] Recording trace 1.7997 (MB)
Press <Enter> or <Ctrl+C> to exit...
Después de presionar <Enter>, se finaliza el seguimiento:
Stopping the trace. This may take up to minutes depending on the application being traced.
Trace completed.
Writing: hellomaui-app-trace.speedscope.json
Visualización de archivos de seguimiento
El --format argumento controla el formato de salida:
-
nettrace(valor predeterminado): se puede ver en PerfView o Visual Studio en Windows -
speedscope: formato JSON que se puede ver en cualquier plataforma en . https://speedscope.app/
Para el análisis multiplataforma, use --format speedscope:
dotnet-trace collect --dsrouter android --format speedscope
Generación de perfiles en Windows
Aunque la herramienta multiplataforma dotnet-trace funciona en Windows, la plataforma ofrece opciones de generación de perfiles nativas adicionales que pueden ser más convenientes.
Uso de Visual Studio Performance Profiler
Visual Studio Performance Profiler proporciona generación de perfiles integrada para aplicaciones .NET. Consulte el recorrido por la función de generación de perfiles de Visual Studio para obtener orientación completa.
Uso de PerfView
PerfView es una eficaz herramienta de análisis de rendimiento libre para Windows que puede generar perfiles de aplicaciones MAUI de .NET con una configuración mínima.
Para generar perfiles con PerfView:
Compile la aplicación para
Releasecon ReadyToRun habilitado:dotnet publish -f net10.0-windows10.0.19041.0 -c Release -p:PublishReadyToRun=trueInicie PerfView y seleccione
Collect>Collect.En el campo Comando, filtre por el archivo ejecutable de la aplicación (por ejemplo,
hellomaui.exe).Haga clic en Iniciar recopilación y, a continuación, inicie manualmente la aplicación.
Haz clic en Detener recopilación una vez que la aplicación haya completado la operación que quieres generar perfiles.
Abra Pilas de CPU para ver información sobre el tiempo o use la pestaña Flame Graph para una vista gráfica.
También puede guardar los datos de PerfView en formato SpeedScope (File>Save View As) para verlos en https://speedscope.app/ para el análisis multiplataforma.
Medición del tiempo de inicio de Windows con PerfView
Para medir los tiempos de inicio precisos en Windows, puede usar PerfView para capturar eventos de Event Tracing for Windows (ETW).
En PerfView, abra
Collect>Collecty expanda Opciones avanzadas.Configurar lo siguiente:
- Habilitación de la base de kernel
- Agregar
Microsoft-Windows-XAML:0x44:Informationala proveedores adicionales
Haga clic en Iniciar recopilación y, a continuación, inicie y cierre la aplicación de 3 a 5 veces.
Haga clic en Detener recopilación.
Abra el informe Eventos y calcule el tiempo de inicio mediante la búsqueda de:
- El evento
Windows Kernel/Process/Startde tu aplicación (ten en cuenta el valorTime MSec) - El primer
Microsoft-Windows-XAML/Frame/Stopevento para el mismo identificador de proceso - Resta la hora de inicio de la hora de detención para obtener la duración del inicio.
- El evento
Ejecute la aplicación varias veces y promedia los resultados para mediciones más precisas.
Uso de dotnet-trace en Windows
Para las aplicaciones de Windows sin empaquetar, puede usar dotnet-trace directamente:
dotnet publish -f net10.0-windows10.0.19041.0 -c Release -p:PublishReadyToRun=true -p:WindowsPackageType=None
dotnet trace collect --format speedscope -- bin\Release\net10.0-windows10.0.19041.0\win10-x64\publish\YourApp.exe
Generación de perfiles en iOS y Mac Catalyst con Instruments
En el caso de las aplicaciones iOS y Mac Catalyst, la herramienta Instruments de Apple proporciona perfiles nativos con información detallada sobre el tiempo de inicio y el rendimiento de la aplicación.
Uso de Instruments para la generación de perfiles de inicio de aplicaciones
Cree tu aplicación para
Releasecon símbolos intactos.dotnet build -c Release -f net10.0-ios -p:NoSymbolStrip=trueLa
NoSymbolStrip=truepropiedad mantiene símbolos nativos en el ejecutable, lo que hace que los seguimientos de pila en Instruments sean mucho más útiles.Instale la aplicación en el dispositivo:
dotnet build -t:Run -c Release -f net10.0-ios -p:NoSymbolStrip=trueInicie Instruments (desde Xcode o ejecutando
open -a Instrumentsen Terminal).Seleccione el dispositivo iOS en la parte superior.
Seleccione la aplicación en la lista de aplicaciones instaladas.
Elija la plantilla de instrumento Lanzamiento de la Aplicación.
Haga clic en Elegir y, a continuación, haga clic en el botón Grabar para iniciar la generación de perfiles.
La aplicación se iniciará automáticamente. Detenga la grabación una vez que la aplicación se haya iniciado por completo.
En los resultados, seleccione la fila Ciclo de vida de la aplicación para ver la escala de tiempo del ciclo de vida. La última fila de la tabla inferior muestra la hora en que se completó el inicio de la aplicación (por ejemplo,
Currently running in the foreground...).
Para obtener más información sobre el uso de Instruments, consulte la documentación de Apple sobre la reducción del tiempo de inicio de la aplicación.
Perfilado del uso de memoria
La generación de perfiles de memoria le ayuda a identificar pérdidas de memoria y a comprender los patrones de asignación de memoria en la aplicación. Use dotnet-gcdump para crear instantáneas de memoria administrada.
Recopilación de volcados de memoria
Para recopilar un volcado de memoria, use el mismo --dsrouter flujo de trabajo que dotnet-trace:
dotnet-gcdump collect --dsrouter android
Utilice --dsrouter android-emu, --dsrouter ios, o --dsrouter ios-sim para otros destinos.
A diferencia del seguimiento de CPU, los volcados de memoria no requieren suspender el inicio de la aplicación. Compile la aplicación con -p:DiagnosticSuspend=false:
dotnet build -t:Run -c Release -f net10.0-android -p:DiagnosticAddress=127.0.0.1 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=false -p:DiagnosticListenMode=connect
Una vez que dotnet-gcdump se conecta, crea un archivo *.gcdump en el directorio actual. Puede abrir este archivo en Visual Studio en Windows o PerfView.
Análisis de volcados de memoria
Al abrir un *.gcdump archivo en Visual Studio, puede hacer lo siguiente:
- Visualización de todos los objetos administrados en memoria
- Ver el recuento total y el tamaño de cada tipo
- Inspeccione el árbol de referencia para comprender lo que mantiene activos los objetos
- Comparación de varias instantáneas para identificar asignaciones crecientes
La herramienta de diagnóstico de uso de memoria (Debug>Windows>Diagnostic Tools) de Visual Studio también permite tomar instantáneas durante la depuración, aunque debe deshabilitar la recarga activa de XAML para obtener resultados precisos.
Sugerencia
Considere la posibilidad de tomar instantáneas de memoria de las compilaciones Release, ya que las rutas de código pueden ser significativamente diferentes cuando se habilita la compilación XAML, la compilación AOT y el recorte.
Diagnóstico de pérdidas de memoria
Las pérdidas de memoria en las aplicaciones MAUI de .NET se manifiestan como un aumento constante del uso de memoria, especialmente durante la navegación repetida o las interacciones. En plataformas móviles, esto puede provocar que el sistema operativo finalice la aplicación debido al consumo excesivo de memoria.
Síntomas de pérdidas de memoria
Un síntoma típico de una pérdida de memoria puede ser:
- Navegar desde la página principal a una página de detalles
- Navegar hacia atrás
- Vuelva a ir a la página de detalles.
- La memoria crece de forma coherente con cada ciclo
Determinar si existe una fuga
Para determinar si una página se está filtrando realmente, use finalizadores con el registro y la recolección forzada de elementos no utilizados durante la depuración.
Agregue un finalizador con funcionalidades de registro a la clase de página.
~MyDetailsPage() => System.Diagnostics.Debug.WriteLine("~MyDetailsPage() finalized");Forzar la recolección de basura en lugares estratégicos (solo para depuración):
public MyDetailsPage() { GC.Collect(); // For debugging purposes only GC.WaitForPendingFinalizers(); InitializeComponent(); }Pruebe una
Releasecompilación y vea la salida de la consola mediante adb logcat (Android) o registros de dispositivos (iOS).
Si el finalizador se ejecuta al navegar fuera de la página, la página está siendo correctamente recogida. Si el finalizador nunca se ejecuta, la página está produciendo una fuga, algo está manteniendo una referencia a la página indefinidamente.
Advertencia
Elimine GC.Collect() las llamadas después de la depuración. Solo son para diagnosticar problemas y nunca deben estar en código de producción.
Restringir la causa
Una vez que haya identificado una fuga, reduzca la causa:
- Comente todo el contenido XAML. ¿Todavía se produce la fuga?
- Convierta en comentario todo el código de C# en el código subyacente. ¿Todavía se produce la fuga?
- Prueba en varias plataformas. ¿Solo sucede en una plataforma?
Por lo general, un vacío ContentPage no debe filtrarse. Al quitar sistemáticamente el código, puede identificar qué control o patrón de código está causando el problema.
Patrones comunes de fuga
Eventos de C#
Los eventos de C# pueden crear referencias circulares que impiden la recolección de basura. Considere un escenario en el que un objeto hijo se suscribe a un evento del padre, pero el padre también mantiene una referencia al objeto hijo. Ambos objetos pueden acabar viviendo para siempre.
Si el origen del evento sobrevive al suscriptor (como Style en Application.Resources), esto puede hacer que se produzca una fuga de páginas completas.
Solución: se usa WeakEventManager para eventos en controles MAUI de .NET o cancela la suscripción a eventos cuando el objeto ya no es necesario.
Referencias circulares en iOS y Mac Catalyst
En iOS y Mac Catalyst, las referencias circulares entre objetos de C# y objetos nativos pueden provocar fugas porque los objetos de C# que son subclases de NSObject existen tanto en el mundo de .NET gestionados por el recolector de basura como en el mundo de Objective-C con conteo de referencias.
Ejemplo de un patrón problemático:
class MyView : UIView
{
public MyView()
{
var picker = new UIDatePicker();
AddSubview(picker); // MyView -> UIDatePicker
picker.ValueChanged += OnValueChanged; // UIDatePicker -> MyView via event handler
}
void OnValueChanged(object? sender, EventArgs e) { }
}
Soluciones:
Crear controladores de eventos
static:static void OnValueChanged(object? sender, EventArgs e) { }Use un objeto proxy que no herede de
NSObject:class MyView : UIView { readonly Proxy _proxy = new(); public MyView() { var picker = new UIDatePicker(); AddSubview(picker); picker.ValueChanged += _proxy.OnValueChanged; } class Proxy { public void OnValueChanged(object? sender, EventArgs e) { } } }
Nota:
Estos problemas de referencia circular son específicos de iOS y Mac Catalyst. Normalmente no se producen en Android o Windows.
Procedimientos recomendados para evitar fugas
Compilaciones de prueba
Release: el comportamiento de la memoria puede diferir significativamente deDebuglas compilaciones debido a optimizaciones, recortes y compilación AOT.Use finalizadores al investigar: agregue finalizadores con registro a objetos clave para identificar rápidamente si están siendo recopilados.
Cancelar la suscripción a eventos: siempre cancela la suscripción de los eventos cuando se eliminan los objetos o ya no se necesitan.
Tenga cuidado con los eventos en objetos de larga duración: Evite permitir que objetos de larga duración (como los de
Application.Resources) mantengan referencias a objetos de corta duración (como páginas o vistas).Perfil regularmente: Incorpore el perfilado de memoria como parte del proceso habitual de pruebas, especialmente después de añadir nuevas características o realizar cambios significativos.
Para obtener información más detallada sobre los patrones y técnicas de pérdida de memoria, consulte el wiki de .NET MAUI sobre pérdidas de memoria.
Enfoques alternativos de generación de perfiles
Registros de inicio de Android ActivityManager
Android registra automáticamente la información de tiempo de inicio a través de ActivityManager. Puede ver estos registros mediante adb logcat:
adb logcat | grep "ActivityManager"
Cuando se inicie la aplicación, verá mensajes como:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
Esto muestra el tiempo necesario para que se muestre la actividad. Se trata de una manera rápida de medir el tiempo de inicio sin necesidad de realizar ningún cambio de código ni herramientas adicionales.
Para obtener más información sobre las técnicas de tiempo de inicio y optimización de la aplicación Android, consulte la documentación de Android sobre el tiempo de inicio de la aplicación.
Medición del inicio basada en registros
Para un enfoque ligero para medir el tiempo de inicio en todas las plataformas, puede registrar mensajes en puntos específicos de la aplicación y medir el tiempo entre ellas:
Agregue un mensaje de registro cuando se cargue la página principal:
Loaded += (sender, e) => Dispatcher.Dispatch(() => Console.WriteLine("loaded"));Utiliza una herramienta como el ejemplo measure-startup para iniciar tu aplicación y medir el tiempo hasta que aparezca el mensaje de registro.
En Android, puede filtrar la
adb logcatsalida para ver los mensajes específicos:adb logcat | grep "loaded"
Este enfoque funciona en todas las plataformas y es útil para escenarios de integración continua o comprobaciones rápidas.
Recursos adicionales
- Wiki de generación de perfiles de MAUI de .NET : wiki completa con escenarios avanzados y solución de problemas
- Guía de seguimiento de Android : instrucciones detalladas de generación de perfiles específicas de Android
- Wiki de generación de perfiles de iOS/macOS - Guía específica para plataformas de Apple
-
Documentación de herramientas de diagnóstico de .NET : documentación oficial de
dotnet-trace,dotnet-dsrouterydotnet-gcdump - Guía del usuario de PerfView : guía detallada sobre el uso de PerfView para la generación de perfiles de Windows