空きメモリが少ない時に、iPhoneの中で何が起きるのか、また調べてみました。

一般的なコンピュータは、物理的に空きメモリが不足すると、OSの判断で、メモリ上のデータを、スワップ領域に逃がして、空きメモリを供給しようとします。iOSの場合は、スワップ領域がないので、また異なった手法が取られます。

Out Of Memory Killerに似てるけど、もう少しやさしいiPhoneOSの空きメモリー制御 - The iPhone Development Playground

また、過去に、iPhoneOS2.xの頃ですが、以下のようなことも書きました。

iPhoneのSafariがいつのまにか終了する条件 - The iPhone Development Playground

iOS4になって、バックグラウンド化されるアプリが激増したことにより、少しやり方が変わったようなので、同じように、また調べてみました。

テストケースについて

今回は、以下の手順でテストしてみました。

  • 標準の状態で、ホーム画面の1ページ目にあるアプリと、Dockに置かれるアプリをすべて起動する。この時点で、空きメモリはかなり少なくなっている。

  • 標準のカメラアプリで写真を1枚撮る。

標準のカメラアプリを選んだ理由は、単純にメモリ使用量が多そうだというだけです。

実際に起こったこと

上記のテストケースを実行する中で、実際起こったことをiPhoneのConsoleログで確認しました。*1

まずは、カメラアプリ自体がmemory warningを受取る。

Thu Jul 22 21:14:26 <> MobileSlideShow[101] : Received memory warning. Level=2

launchd*2が、いくつかのプロセスをkillする。これは、否応無しの強制終了ですね。

Thu Jul 22 21:14:27 <> com.apple.launchd[1] (UIKitApplication:com.apple.stocks[0x51a2][555]) : (UIKitApplication:com.apple.stocks[0x51a2]) Exited: Killed
Thu Jul 22 21:14:27 <> com.apple.launchd[1] (UIKitApplication:com.apple.Maps[0x9f0a][83]) : (UIKitApplication:com.apple.Maps[0x9f0a]) Exited: Killed
Thu Jul 22 21:14:27 <> com.apple.launchd[1] (UIKitApplication:com.apple.AppStore[0x4978][559]) : (UIKitApplication:com.apple.AppStore[0x4978]) Exited: Killed
Thu Jul 22 21:14:27 <> com.apple.launchd[1] (UIKitApplication:com.apple.weather[0xe312][562]) : (UIKitApplication:com.apple.weather[0xe312]) Exited: Killed
Thu Jul 22 21:14:27 <> com.apple.launchd[1] (UIKitApplication:com.apple.mobiletimer[0xc065][563]) : (UIKitApplication:com.apple.mobiletimer[0xc065]) Exited: Killed
Thu Jul 22 21:14:27 <> com.apple.launchd[1] (UIKitApplication:com.apple.calculator[0x83f4][564]) : (UIKitApplication:com.apple.calculator[0x83f4]) Exited: Killed
Thu Jul 22 21:14:27 <> com.apple.launchd[1] (UIKitApplication:com.apple.mobilenotes[0x53bc][565]) : (UIKitApplication:com.apple.mobilenotes[0x53bc]) Exited: Killed
Thu Jul 22 21:14:28 <> com.apple.launchd[1] (UIKitApplication:com.apple.Preferences[0x3c08][566]) : (UIKitApplication:com.apple.Preferences[0x3c08]) Exited: Killed
Thu Jul 22 21:14:28 <> com.apple.launchd[1] (UIKitApplication:com.apple.MobileAddressBook[0x8471][568]) : (UIKitApplication:com.apple.MobileAddressBook[0x8471]) Exited: Killed
Thu Jul 22 21:14:28 <> com.apple.launchd[1] (UIKitApplication:com.apple.VoiceMemos[0x2037][569]) : (UIKitApplication:com.apple.VoiceMemos[0x2037]) Exited: Killed

SpringBoardが、アプリがkillされたことを検知する。

Thu Jul 22 21:14:27 <> SpringBoard[28] : Application 'マップ' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:28 <> SpringBoard[28] : Application '株価' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:28 <> SpringBoard[28] : Application 'App Store' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:28 <> SpringBoard[28] : Application '天気' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:28 <> SpringBoard[28] : Application '時計' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:29 <> SpringBoard[28] : Application '計算機' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:29 <> SpringBoard[28] : Application 'メモ' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:29 <> SpringBoard[28] : Application '設定' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:29 <> SpringBoard[28] : Application '連絡先' exited abnormally with signal 9: Killed
Thu Jul 22 21:14:29 <> SpringBoard[28] : Application 'ボイスメモ' exited abnormally with signal 9: Killed

CrashReportが生成される。

これは、「Low Memory」というタイプのCrashReportですね。ふつうに使っているだけでも、そこそこ出ると思います。
今のところ、この「Low Memory」のCrashReportを出なくする方法はないと思います。

Thu Jul 22 21:14:30 <> ReportCrash[594] : Saved crashreport to /Library/Logs/CrashReporter/LowMemory-2010-07-22-211430.plist using uid: 0 gid: 0, synthetic_euid: 0 egid: 0

生き残ったアプリはどれか?

とりあえず、以下のアプリのプロセスは、killされずに残っていました。どういう基準でkillされるものが選別されたのかは不明ですが、恐らく、suspend状態のものが、優先的にkillされているのでしょうね。残ったものは、何となくsuspend状態ではないような気がします。

空きメモリはどうなったか?

プロセスが強制終了されたことによって、空きメモリは増えました。当然と言えば、当然の結果ですが。。

まとめ

このように、ごく普通の状況で、バックグラウンド化されてsuspend状態のアプリは、強制終了される可能性があります。裏を返せば、いつ強制終了されても、問題が起きないようにしておくことが重要だということですね。
あと、ユーザの立場からは、こういう形で強制終了されたアプリは、「最近使ったアプリケーション」のアイコンリストからは消えるわけではないことも、理解しておく必要があると思います。

そのほかに気になるところは、バックグラウンドでひっそりと動きながら、位置情報のトラッキングや音楽の再生をしているアプリが、こういう状況でどうなるのかということですね。また、機会があれば、調べてみたいと思います。
(そういうタイプのアプリは、常にいきなり強制終了ではないように思いますが、まだ確信はない状態です。。)

最後に。。

過去の記事で、「メモリ解放(?)機能」について、いろいろ試行錯誤したこともあり、誤解されている方もいらっしゃるようですが、私のアプリでは、そのような機能を実装する予定はありません。ご理解、ご了承のほどお願いいたします。

*1:Consoleログは、アプリ開発環境であるXcodeを使うことで見ることができます。

*2:プロセスの起動を制御するデーモンプロセス。Undocumented Mac OS X:第1回 initを置き換えるlaunchd【前編】 (2/3) - ITmedia エンタープライズを参照