私の iPad アプリは MonoTouch で開発されています。これは、メモリ管理の地獄をすべて回避したかったためですが、そうではないようです。シミュレーターではすべて正常に動作しますが、デバイスでアプリをテストしたところ、いくつかのメモリ警告の後、OS によってすぐに強制終了されることがわかりました。私のアプリは単純な画像ブラウザーです。いくつかの PNG 画像を読み込み、UIScrollView 内のいくつかの UIViews を使用してそれらを表示し、タッチすると次または前の画像を読み込みます。シミュレーターでは問題なく動作します。しかし、約 6 ~ 11 個のイメージをロードおよびアンロードした後のデバイスでは、メモリ警告が表示され始め、突然プロセスが強制終了されます。すべてのインスタンス化サイクルを確認し、新しいイメージをロードする前にすべての参照を正しく削除しました。
そこで、Instruments を起動し、iPad でアプリのメモリ割り当てのプロファイリングを開始しました。そこで私は、ライブ バイトが約 5 ~ 9 MB しかないことを発見しました。それはLive Bytesです)それは殺されています!これは、私のアプリの Instruments プロファイリング セッションのスクリーンショットです。
ヒープショット シーケンスは次のとおりです。
小さな漏れもありますが、犯人になるほど大きくはないと思います。これらはすべて、iOS 5.1 で UIScrollView をリリースする際の既知の問題である strdup からの 48 バイトのリークです。
すべてが正常に見え、割り当てられたライブ バイトがまだ 5 MB であっても、私のアプリの REAL メモリは指数関数的に増加してから、iPad では最大 50 MB まで、iPhone4S では最大 314 MB まで、メモリ モニタによって報告されます。
問題がどこにあるのかを発見するための方法やユーティリティがあるかどうか、誰かが教えてくれますか? モノタッチガベージコレクタのバグですか?または、正しく処分していないオブジェクトがありますか? そして、プロファイラーでそれらを見つけるにはどうすればよいですか? コードを 2 日間チェックしましたが、すべて問題ないようです。
ロード/インスタンス化/破棄サイクルのコードは次のとおりです。
void StartImageLoadingThread()
{
tokenSource = new CancellationTokenSource ();
token = tokenSource.Token;
Task task1 = new Task( () => PerformLoadImageTask(token),token);
task1.Start();
}
void PerformLoadImageTask(CancellationToken token)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Task {0}: Cancelling", Task.CurrentId);
return;
}
current_uiimage_A = UIImage.FromFileUncached(file_name);
page_A_image_view.Image = current_uiimage_A;
}
void UnloadImageAFromMemory()
{
page_A_image_view.Image = null;
current_uiimage_A.Dispose();
current_uiimage_A = null;
}
正しく破棄されていないオブジェクトをキャッチする方法はありますか? Instruments は、ライブ バイト数が少なく、リークがほぼゼロであると報告していますが、なぜデッド オブジェクトが破棄されないのでしょうか? アプリで数分間何も起こらなかったとしても、コードで明示的に呼び出しても、GC は機能していないようです。新しい実験的なガベージ コレクターも試してみましたが、アプリを強制終了するのはさらに悪く、より迅速です。
Xamarin Web サイトで、メモリ警告のトラブルシューティングや不適切な割り当ての追跡に関するガイドラインやステップバイステップ ガイドを見つけることができません。
どんな助けや提案も大歓迎です、ありがとう!
更新: 一部の画像と uiview のサイズと解像度を減らしました。Live Bytes は 9 MB から 5 MB に減少しましたが、メモリ警告が表示された後、アプリは依然として強制終了されます。
更新 2: ハビエルが提案したように、バックグラウンド タスクを削除して直接呼び出しを行ったところ、メモリ リークはなくなりました! MonoTouch ガベージ コレクターにバグがあり、UIImages が割り当てられ、別のスレッドで破棄されたときにメモリを収集できないようです。しかし今、スクロールすると私のアプリがひどく反応しなくなったので、別のスレッドでそれを行うための解決策を見つける必要があります! しかし、どのように?