目次
はじめに
.NET MAUIアプリを作る際に一番苦労するのは、メモリーリークの対応だと思います。ただし、Visual Studioにあるパフォーマンスプロファイラーが.NET MAUIのモバイルアプリで使えないなど、Android Studioのプロファイラーほど気楽には使うことはできません。
https://github.com/dotnet/maui/wiki/Memory-Leaks
情けない話ですが、筆者はMemory Leaksの欄を読んでも、結局dmpまで行きつくことはできませんでした。
メモリーリークを検知する簡単な方法ですが、コントリビュータの方が作ったMemoryToolkitというツールをアプリに埋め込むのが手軽でしたので、ここでご紹介します。
MemoryToolkitをアプリに埋め込む
githubのREADMEのQuick Startに詳細がありますが、こちらでもご紹介します。
・右の[ソリューションエクスプローラー]の[プロジェクト]を右クリック=>[Nugetパッケージの管理]をクリックし、[Nugetパッケージマネージャー]を表示
・検索窓で”AdamE.MemoryToolkit.Maui”と入力して、表示されたライブラリをインストール
・CreateMauiApp()内に以下を記載
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
// ここから
#if DEBUG
builder.Logging.AddDebug();
// Ensure UseLeakDetection is called after logging has been configured!
builder.UseLeakDetection(collectionTarget =>
{
// This callback will run any time a leak is detected.
Application.Current?.MainPage?.DisplayAlert("💦Leak Detected💦",
$"❗🧟❗{collectionTarget.Name} is a zombie!", "OK");
});
#endif
// ここまで
return builder.Build();
・検知したい各画面のxamlファイルに以下を記載MemoryToolkit.Mauiの参照とLeakMonitorBehavior.Cascade=”True”を追加
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SampleCollectionViewApp.ItemPage"
xmlns:mtk="clr-namespace:MemoryToolkit.Maui;assembly=MemoryToolkit.Maui"
mtk:LeakMonitorBehavior.Cascade="True">
...
</ContentPage>
・これで事前準備が完了
メモリーリークの検知
実際にメモリーリークを検知します。
Microsoft.Maui.Controls, Microsoft.Maui.Controls.Compatibilityの8.0.20では、iOSのモーダル表示され、元画面に戻ると必ずメモリーリークになるため、遷移する際は以下のようにモーダル表示を指定します。
await Navigation.PushModalAsync(new Modal());
モーダルを表示してからモーダルを閉じると、画面とログで以下のようなアラートが表示されます。
アプリのメモリ使用量を表示する
上記でメモリーリークの「する/しない」の検知はできました。次はこの検知アプリが本当に正しいか、裏取りもかねてアプリのメモリ使用量を画面に表示します。こちらもMemoryToolkitのサンプルアプリを参考にしています。
public CollectionPage()
{
// 事前に動的にメモリー開放する
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
// 画面の初期化
InitializeComponent();
// メモリ使用量を取得してXAMLで定義したHeapLabelラベルに表示する
int heapSize = (int)(GC.GetTotalMemory(false) / 1024d);
HeapLabel.Text = $"Heap Size: {heapSize} KB";
// 以下画面表示
・・・
}
以下のように画面に表示できました。これで、画面遷移しても無限にメモリー使用量が増えなければ、成功です。