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
を数回押してから カメラアイコン を押してみましょう。
上図のように、追加した byte データが記録されています。
次に、myButton2
を数回押してから カメラアイコン を押してみましょう。
今度は 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
を何度か押すと、下図のようになります。
ボタンを押すたびにメモリ使用量が増えているのが確認できます。
(実は 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 にとても似ていますね。
各種プロファイラ自体の使い方や機能については、私も全然把握できてないので、知見が溜まったらまた何か書きます。