Xamarin Profiler と Android Profiler を併用して Xamarin Android アプリのメモリ使用量を測定する

Xamarin 製アプリのメモリのプロファイリングは、

  • .NET(mono ランタイム) が管理するオブジェクト
  • Java(Dalvik) が管理するオブジェクト

を意識する必要があります。

使用するツール

.NET(mono ランタイム) が管理するオブジェクトのメモリ測定には、

を使用します。これは Visual Studio と連携するアプリで、IDE から Run

Start Profiling とすると起動できるものです。

Java(Dalvik) が管理するオブジェクトのメモリ測定には、

を使用します。こちらは Android Studio をインストールすれば一緒に入っています。

試してみた

Xamarin Profiler

Xamarin Android で、画面に2つのボタンを配置し、それぞれ次のような処理を行うコードを書きます。

[Activity(Label = "LeakSample", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity
{
    System.IO.MemoryStream netStream = new System.IO.MemoryStream();
    Java.IO.ByteArrayOutputStream javaStream = new Java.IO.ByteArrayOutputStream();

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        FindViewById<Button>(Resource.Id.myButton1).Click += (_, __) =>
        {
            var size = 10 * 1024 * 1024;
            netStream.Write(new byte[size], 0, size);
        };

        FindViewById<Button>(Resource.Id.myButton2).Click += (_, __) =>
        {
            var size = 10 * 1024 * 1024;
            javaStream.Write(new byte[size]);
        };
    }
}

myButton1 を押したときには、 .NET のクラスである System.IO.MemoryStream にデータ追加します。

myButton2 を押したときには、 Java のクラスである Java.IO.ByteArrayOutputStream にデータ追加します。

こんなプログラムを Run > Start Profiling で起動してみます。 アプリが起動する前に Xamarin Profiler が起動します。Choose target は既に起動したい Android アプリが設定されているので、「割り当て」を選択して「Next」します。

次の画面の「Enable automatic snapshots」をチェックすると自動的(一定間隔で)にメモリのスナップショットを記録しますがこれはお好みで。

「プリファイリングの開始」を押すとアプリが起動します。 Xamarin Profiler の上部にある カメラアイコン を押すと任意のタイミングでメモリ状態を記録できます。

myButton1 を数回押してから カメラアイコン を押してみましょう。

image.png

上図のように、追加した byte データが記録されています。

次に、myButton2 を数回押してから カメラアイコン を押してみましょう。

image.png

今度は Dalvik 管轄のオブジェクトへデータを追加したので Xamarin Profiler ではそのクラスは観測できません。(ワーキングセットは増えてるのでそれは観測できる?)

Android Profiler with Xamarin.Android apps

Dalvik が管理している領域のプロファイリングは Android Profiler を使います。 Xamarin であっても「それは Android/Java API をラップしただけ」の実体はネイティブ Android アプリなので、Android SDK のツールは使えるのです。

Android Studio を起動して適当な Android Apps のプロジェクトを開くか作ります(これはダミーです)。 次に メニュー > View > Tool Windows > Profiler で下部に Profiler ペインが開きます。 SESSIONS の横の「+」を押して、対象の端末 > Other processes > 対象のアプリID を選択すると、プロファイリングが始まります。

この状態で、アプリの myButton2 を何度か押すと、下図のようになります。

image.png

ボタンを押すたびにメモリ使用量が増えているのが確認できます。 (実は myButton1 を押すと、最初の1回はメモリ使用量が増えます。".NET だけ" には留まらないなにか、があるのでしょうか、おそらく。)

まとめ

このように Xamarin(.NET)側のプロファイリングには Xamarin Profiler が、Java/Android API使用部のプロファイリングには Android Profiler がそれぞれ使用でき、同時利用あるいは併用することで、 Xamarin Android アプリの計測ができます。

これは Xamarin.Forms アプリでも同様です。その場合、Custom Renderer やライブラリの Android 依存な箇所の計測は Android Profiler に頼ることがでてくるでしょう。

また、Xamarin Profiler は Xamarin.iOS アプリの計測もできます。というか Xamarin Profiler の Look&Feel は Xcode - Instruments にとても似ていますね。

各種プロファイラ自体の使い方や機能については、私も全然把握できてないので、知見が溜まったらまた何か書きます。