個人的なメモ

Tomohiro Suzuki @hiro128_777 のブログです。Xamarin に関する事を中心に書いています。 Microsoft MVP for Development Technologies 2017- 本ブログと所属組織の公式見解は関係ございません。

Xamarin.iOS Deep Dive その2 Xamarin.iOS は簡単にメモリーリークしてしまう

はじめに


こんにちは、@hiro128_777です。
iOSDC で 以下の通り Xamarin.iOS の仕組みについてお話させていただきました。


www.slideshare.net
www.youtube.com


ですが、時間が足りなくて話しきれなかったことが多いので、blog でもう少しこの話題を掘り下げて説明していこうと思います。


前回のお話はこちらです。

hiro128.hatenablog.jp



今回は Windows で 開発してきた皆さんが Xamarin.iOS でハマりがちなメモリーリークについてご説明します。

Windows と Xamarin.iOS の簡単なサンプルコードでメモリーリークの状況をそれぞれ確認する。

View 上にボタンがあり、ボタンを押すと View を閉じるサンプルコードです。 Windows と Xamarin.iOS で全く同じことをしています。

実際に動作するサンプルコードは GitHub にアップしてありますので是非動かしてみてください。GitHub にアップしたサンプルではオブジェクトの初期化、破棄、ファイナライズでそれぞれトレースを出力するようにしています。 blog のコードは簡略化してあります。

ますは Windows のコードです。

Windows Forms
void InitializeComponent()
{
    var buttonClose = new Button();
    buttonClose.Click += ButtonClose_Click;
    Controls.Add(buttonClose); 
} 

void ButtonClose_Click(object sender, EventArgs e) => Close();

フルバージョンはこちらです。
github.com


とても簡単なコードですね。当然、メモリーリークなどしません。

次に、Xamarin.iOS で同じことをやってみましょう


Xamarin.iOS
public override void ViewDidLoad()
{
    base.ViewDidLoad();

    var dismissViewButton = new UIButton();
    dismissViewButton.TouchUpInside += DismissViewButton_TouchUpInside;
    View.AddSubview(dismissViewButton); 
} 

void DismissViewButton_TouchUpInside(object sender, EventArgs e)
    => DismissViewController(truenull);

フルバージョンはこちらです。
github.com

はい、メモリーリークしました!

全く同じ意味のコードを書いているのに、Xamarin.iOS だけメモリーリークしてしまいます。

ただし、実はこの現象は、どちらかといえばメモリーリークする Xamarin.iOS の方がプログラムの動きとしてはむしろ当たり前で、メモリーリークしない、Windows がすごいと言った方が正確です。Windows .NETGC はなかなか賢くて、このような単純なパターンであれば本来メモリーリークしてもおかしくないコードでもしっかり GC が回収してくれます。

なぜ、Xamarin.iOS ではメモリーリークするのか


前回も言った通り、Xamarin.iOS は「攻めた設計」であり、.NET と iOS API の相互運用という 「禁断の果実」に手を出しているからメモリーリークしてしまいます。

具体的には

という機能を使えるようにした「副作用」です。

では、次回以降では、Xamarin.iOS でメモリーリークする詳しいメカニズムを見ていきましょう。

今回は以上となります。


次回はこちらです。
hiro128.hatenablog.jp