iPhoneのSafariがいつのまにか終了する条件

以前、SysStats Liteを使っていて気づいたこと - The iPhone Development Playgroundの中で、以下のようなことを書きました。

例えば、Safariを起動してWebページを見た後に、上記の「稼働中のアプリケーション」画面を開くと、Safariが「稼働中」になります。その後しばらく適当に操作していると、メモリの空きが急に増えることがあります。そのときに、「稼働中のアプリケーション」画面を開くと、Safariが「停止中」になっていたりします。

これが、正常な挙動だと考えると、「空きメモリが少なくなって来ると、バックグラウンドで動いているSafariが終了し、メモリを解放してくれる」というふうに取れます。

そんな気の利いた機能が、iPhoneOS 2.2で追加されたんでしょうかね。それとも、ただ単に、バックグラウンドのSafariが異常終了しただけなんでしょうか。。。

SysStats Liteを使っていて気づいたこと - The iPhone Development Playground

最近いろいろと調べていると、どうも、「空きメモリが少なくなって来ると、バックグラウンドで動いているSafariが終了し、メモリを解放してくれる」というのが事実なようです。検証のために、SysStats Liteに、とにかくメモリを使いまくるようなコードを追加し、iPhoneで動かしてみました。
Xcodeのオーガナイザの、Consoleで見ると、以下のような感じになります。

  • まず、Safariが、自分の確保しているメモリを解放しようとする。

01:18:37 unknown MobileSafari[942] : Safari got memory level warning, killing all documents except active.]]

  • 空きメモリが少ないことを示す注意メッセージが出た後、SpringBoard(ホーム画面のプロセス)が、Safariに終了指示を出す。

01:19:34 unknown configd[21] : kernel memory event (90), free: 258, active: 1812, inactive: 1079, purgeable: 0, wired: 8202
01:19:34 unknown SpringBoard[771] : Memory level is urgent (10%). Asking 'Safari' to quit.

  • その指示に従って、Safariが自分で終了する。

01:19:34 unknown MobileSafari[942] : Safari got memory level urgent while suspended, self-terminating
01:19:34 unknown com.apple.launchd[1] : Exited with exit code: 101]]

  • さらに、そのまま進めて行くと、iPodなど、他のアプリも同じように終了する。

01:20:51 unknown configd[21] : kernel memory event (90), free: 374, active: 1808, inactive: 950, purgeable: 0, wired: 7992
01:20:51 unknown SpringBoard[771] : Memory level is urgent (10%). Asking '\M-c\M^C\M-!\M-c\M^C\M-<\M-c\M^C\M-+' to quit.
01:20:51 unknown com.apple.launchd[1] : Exited with exit code: 101
01:20:51 unknown SpringBoard[771] : Memory level is not normal (10%). Delaying auto-relaunch of '\M-c\M^C\M-!\M-c\M^C\M-<\M-c\M^C\M-+' for 30 seconds.
01:20:51 unknown SpringBoard[771] : Memory level is urgent (10%). Asking 'iPod' to quit.
01:20:52 unknown com.apple.launchd[1] : Exited with exit code: 101

  • そして、ついに、SysStats Liteにも終了指示が来たが、それに対処することができないため、そのままさらに動き続けてしまっている。

01:21:31 unknown configd[21] : kernel memory event (90), free: 374, active: 1707, inactive: 996, purgeable: 96, wired: 7526
01:21:31 unknown SpringBoard[771] : Memory level is urgent (10%). Asking 'SysStatsLite' to quit.
01:21:31 unknown SpringBoard[771] : Writing low memory report regarding 'SysStatsLite'
01:21:33 unknown ReportCrash[951] : Saved crashreport to /Library/Logs/CrashReporter/SysStatsLite-2008-12-27-012132.plist using uid: 0 gid: 0, synthetic_euid: 0 egid: 0
01:21:46 unknown SpringBoard[771] : Application 'SysStatsLite' got sufficiently warned but is still alive, killing it. Jetsam level: 10%
01:21:46 unknown SpringBoard[771] : Writing low memory report regarding 'SysStatsLite'

  • 最終的には、もう終了できるアプリがないので、SpringBoard自身や電話機能までも終了して、再起動となってしまった。

01:21:57 unknown SpringBoard[771] : Memory level is critical (5%). No apps to kill. Will kill SpringBoard
01:21:57 unknown SpringBoard[771] : Jetsaming SpringBoard...
01:21:57 unknown com.apple.launchd[1] : Exited with exit code: 1
01:21:57 unknown UIKitApplication:com.apple.mobilephone[0x345f][774] : Terminating in response to SpringBoard's termination.

上記を整理すると、iPhoneは、メモリ不足を検知すると、以下のような制御をしていることになるかと思います。

  • まずは、バックグラウンドで稼働中のSafariiPodのプロセスを終了して、空きメモリを作ろうとする。
  • それでもだめなら、ユーザが使用しているフォアグラウンドのアプリケーションを終了させる。
  • その時点で、終了できるアプリが見つからなければ、SpringBoardは、自分を終了して再起動する。
    • iPhoneが再起動したように見える。Macでいうと、Finderの再起動に類似する状態である。当然のことながら、この時点で、空きメモリは大幅に増える。

これらは、少ないメモリをやり繰りしながら動かして行くための、緊急避難的な仕組みとしては、適切な方式だと思います。
Safariが最初に終了させられているのは、最も影響が少なそうだからでしょうかね。。。
今回のテストは、ちょっとやり過ぎで、SpringBoardが再起動するところまで行ってしまいましたが、バックグラウンドのSafariが、いつのまにか終了しているのも、そのような流れによるものだということが見えてきました。
また、裏を返せば、この性質を利用することで、SysStats LiteからSafariを終了させることも、できなくはなさそうです。ただ、結局は、わざとシステムを悪い状態にすることになるので、他にどんな影響が出るかはわかりません。こんな無理矢理な副作用的な方法でやっていいのかどうかは、私の中では、かなり疑問が残ります。
バックグラウンドのSafariを終了することは、基本的には問題ないと思われるので、できれば、Safariを終了させるAPIが提供されることが望ましいですね。