Administración del uso de memoria en aplicaciones de escritorio de SDK de Aplicaciones para Windows

La administración eficaz de memoria ayuda a que la aplicación funcione bien, especialmente en dispositivos con recursos limitados. En este artículo se describen las estrategias para administrar la memoria en una aplicación de escritorio de SDK de Aplicaciones para Windows, especialmente cuando la ventana de la aplicación no está visible.

Importante

El sistema no suspende automáticamente las aplicaciones de escritorio. Siguen usando memoria mientras se ejecutan. La administración proactiva de memoria mejora la capacidad de respuesta general del sistema y la duración de la batería.

Supervisión del uso de la memoria

Use la clase Windows.System.MemoryManager para comprobar el consumo de memoria de la aplicación y el estado de la memoria de todo el sistema:

ulong appMemoryUsage = Windows.System.MemoryManager.AppMemoryUsage;
ulong appMemoryLimit = Windows.System.MemoryManager.AppMemoryUsageLimit;
Windows.System.AppMemoryUsageLevel level = Windows.System.MemoryManager.AppMemoryUsageLevel;

System.Diagnostics.Debug.WriteLine(
    $"Memory: {appMemoryUsage / 1024 / 1024} MB used, " +
    $"limit: {appMemoryLimit / 1024 / 1024} MB, level: {level}");

También puede suscribirse a MemoryManager.AppMemoryUsageLimitChanging y MemoryManager.AppMemoryUsageIncreased para reaccionar ante la presión de memoria.

Reducir la memoria cuando la ventana está oculta

Aunque el sistema no suspende la aplicación de escritorio, puede reducir el consumo de memoria cuando la ventana está minimizada o oculta. Esto hace que más recursos estén disponibles para la aplicación en primer plano y amplía la duración de la batería.

Detectar cuándo está oculta la ventana

Microsoft.UI.Xaml.Window no expone ningún VisibilityChanged evento. En su lugar, use el Window.Activated evento para detectar cuándo la ventana pierde el foco o usar AppWindow.Changed para detectar cuándo se minimiza:

var m_window = App_Window;

void ReduceMemoryUsage() { }
void RestoreResources() { }

m_window.Activated += (sender, args) =>
{
    if (args.WindowActivationState == WindowActivationState.Deactivated)
    {
        // Window lost focus — consider reducing memory usage
        ReduceMemoryUsage();
    }
    else
    {
        // Window is active — reload resources
        RestoreResources();
    }
};

// To specifically detect minimize, use AppWindow.Changed
var appWindow = m_window.AppWindow;
appWindow.Changed += (sender, args) =>
{
    if (args.DidPresenterChange &&
        sender.Presenter is OverlappedPresenter presenter &&
        presenter.State == OverlappedPresenterState.Minimized)
    {
        // Window is minimized — reduce memory usage
        ReduceMemoryUsage();
    }
};

Qué publicar

Cuando la ventana esté oculta, considere la posibilidad de liberar:

  • Imágenes almacenadas en caché y mapas de bits : elimine mapas de bits grandes que solo son necesarios para mostrarse.
  • Recursos de destino de representación : libera los recursos de GPU usados para la representación.
  • Datos del modelo de vista : borra las colecciones o los datos almacenados en caché que se pueden volver a cargar cuando el usuario vuelve.
  • Historial de navegación : si la aplicación tiene una pila de navegación, borre las páginas almacenadas en caché.
private System.Collections.Generic.List<object>? _imageCache;
private global::Microsoft.UI.Xaml.Window m_window = App_Window;

private void ReduceMemoryUsage()
{
    // Release cached images
    _imageCache?.Clear();

    // Clear navigation cache
    if (m_window.Content is Frame rootFrame)
    {
        rootFrame.CacheSize = 0;
    }

    // Hint the GC to collect if appropriate, without forcing a blocking collection.
    // Only call this in response to system memory pressure, not on every hide.
    GC.Collect(2, GCCollectionMode.Optimized, blocking: false);
}

private void RestoreResources()
{
    // Restore navigation cache
    if (m_window.Content is Frame rootFrame)
    {
        rootFrame.CacheSize = 10;
    }

    // Reload other resources as needed
}

Controlar la presión de memoria del sistema

Regístrese para el evento MemoryManager.AppMemoryUsageIncreased para detectar cuándo aumenta la presión de memoria del sistema:

void ReduceMemoryUsage() { }

Windows.System.MemoryManager.AppMemoryUsageIncreased += (sender, e) =>
{
    var level = Windows.System.MemoryManager.AppMemoryUsageLevel;

    if (level == Windows.System.AppMemoryUsageLevel.OverLimit ||
        level == Windows.System.AppMemoryUsageLevel.High)
    {
        ReduceMemoryUsage();
    }
};

Tip

Aunque el sistema no finaliza automáticamente las aplicaciones de escritorio para liberar memoria (a diferencia de UWP), reducir el uso de memoria cuando hay presión de memoria mantiene la capacidad de respuesta del sistema y evita posibles situaciones de memoria insuficiente.

Prácticas recomendadas

  • Libera lo que puedes volver a cargar. Libere solo los recursos que pueda reconstruir más adelante a partir del disco, la red o mediante cálculo.
  • Reducir gradualmente. Comience liberando primero los elementos más grandes (imágenes, cachés y recopilaciones de datos).
  • Prueba en dispositivos con poca memoria. Compruebe que la administración de memoria funciona en dispositivos con 4 GB o menos de RAM.
  • Evite mantener objetos grandes en campos estáticos. En su lugar, use patrones de carga diferida.