Windows アプリ SDK デスクトップ アプリでのメモリ使用量の管理

効率的なメモリ管理は、特にリソースが限られているデバイスでアプリのパフォーマンスを向上するのに役立ちます。 この記事では、特にアプリ ウィンドウが表示されない場合に、Windows アプリ SDK デスクトップ アプリでメモリを管理する方法について説明します。

Important

デスクトップ アプリは、システムによって 自動的に中断されません 。 実行中にメモリを消費し続けます。 プロアクティブ メモリ管理により、システム全体の応答性とバッテリ寿命が向上します。

メモリ使用量の監視

Windows.System.MemoryManager クラスを使用して、アプリのメモリ使用量とシステム全体のメモリ状態を確認します。

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}");

MemoryManager.AppMemoryUsageLimitChangingMemoryManager.AppMemoryUsageIncreased をサブスクライブして、メモリ不足に応答することもできます。

ウィンドウが非表示のときにメモリを減らす

システムはデスクトップ アプリを中断しませんが、ウィンドウが最小化または非表示になっている場合にメモリ消費量を減らすことができます。 これにより、フォアグラウンド アプリで使用できるリソースが増え、バッテリ寿命が延びます。

ウィンドウが非表示になっていることを検出する

Microsoft.UI.Xaml.WindowVisibilityChanged イベントを公開していません。 代わりに、 Window.Activated イベントを使用して、ウィンドウがフォーカスを失ったときに検出するか、 AppWindow.Changed を使用して最小化されたタイミングを検出します。

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();
    }
};

リリースする内容

ウィンドウが非表示になっている場合は、次を解放することを検討してください:

  • キャッシュされたイメージとビットマップ - 表示にのみ必要な大きなビットマップを破棄します。
  • レンダー ターゲット リソース — レンダリングに使用される GPU リソースを解放します。
  • ビュー モデル データ - ユーザーが戻ったときに再読み込みできるコレクションまたはキャッシュされたデータをクリアします。
  • ナビゲーション履歴 - アプリにナビゲーション スタックがある場合は、キャッシュされたページをクリアします。
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
}

システムメモリの負荷を処理する

MemoryManager.AppMemoryUsageIncreased イベントに登録して、システムメモリの負荷が上昇したことを検出します。

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

デスクトップ アプリは、(UWP とは異なり) メモリを解放するためにシステムによって自動的に終了されるわけではありませんが、メモリ不足時のフットプリントを減らすと、システムの応答性が維持され、メモリ不足の可能性を回避できます。

ベスト プラクティス

  • 再読み込みできる内容を解放します。 後でディスク、ネットワーク、または計算から再構築できるリソースのみを解放します。
  • 徐々に減らします。 最初に最大の項目 (イメージ、キャッシュ、データ コレクション) を解放することから始めます。
  • メモリ不足のデバイスでテストします。 メモリ管理が 4 GB 以下の RAM を持つデバイスで動作することを確認します。
  • 静的フィールドに大きなオブジェクトを保持しないようにします。 代わりに遅延読み込みパターンを使用してください。