MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

Firefox OSの低メモリ管理

Firefox OSはメモリが制約された端末で実行され、そうしたシステムにおいて、使用可能なメモリをアプリが使い果たすのは簡単です。システムで使用可能なメモリが使い果たされた時、カーネルはメモリを解放するために、その他のプロセスを停止しなければなりません。この記事では低メモリキラーと低メモリ通知 ( この2つの端末上システムはシステムが低メモリになった時に、メインシステムを続けるためにどのプロセスを停止するかを管理する ) が動作する方法を説明します。

Firefox OS の操作はマルチプロセス ( 1つ動作している基本システムサービス「メインプロセス」と、潜在的なたくさんの「子プロセス」) を含んでいます。一般的に、各アプリはその子プロセスとして実行されます。Firefox OS 環境上でアプリケーションはユーザーによって滅多に終了される事が無いので、新しいアプリがメモリを必要としたときや起動しているアプリが更なるメモリを必要としたときにメモリ空間を作る事が出来るようにシステムは自動でアプリのライフサイクルを管理しています。

2つのサブシステム (低メモリキラー (LMK) 低メモリ通知) はこの管理に利用されています。

低メモリキラー(LMK)

LMK は メモリの要求があったときにメモリ空間を確保するためにプロセスを終了させる Android カーネル のサブシステムです。メモリを確保するために最初に終了させるプロセスを選択するために、/proc/<pid>/oom_adj か /proc/<pid>/oom_score_adj ファイルによって各プロセスは優先度を決められています。プロセスの優先度は adjustment スコアまたは、oom_adj として知られています。oom_adj の値は小さいほど優先度の高いプロセスです。

一般的に、大きい adjustment スコアはプロセスが終了されやすくなります。 LKM は一定のメモリ空き容量と、最小の adjustment スコアに応じて、複数のレベルを提供しています。システムの空き容量がある一定のレベルよりも低くなったときはいつも、望ましいレベルで定義された最小の adjustment スコアよりも高い adjustment スコアのプロセスは終了します。LKM は最初に大きいプロセスを終了させます。そして、閾値以上にメモリが確保されるまでくりかえします。

: バックグラウンドのアプリがLMKに停止された時、タスクマネージャで端をスワイプすると"ゾンビアプリ"になっています: 次にそのアプリをブラウズした時、復活するでしょう。この状態で維持できるアプリの最大数は現在10個です。

: 端末がメモリ不足になった時に停止されたプロセスは、必ずしもOOM(メモリ不足)の "原因" とは限りません。

プロセスの優先順位

Firefox OS では、アプリは以下の優先順ポリシーに従って終了されます。このポリシーは各アプリケーションに優先度を与え、このレベル(現在は prefs のセット値として設定されている)に OOM adjustment スコアを関連づける事によって実現しています。

  1. 最初に終了されるアプリは、最初に利用して起動しているバックグラウンドアプリです。
  2. ユーザーによって認識されているバックグラウンドアプリは次に終了されます。(例えば、音楽プレイヤーがバックグラウンドで音楽を再生していたり、アプリが高い優先度を持っていたり、CPU  wakelock やシステムメッセージのハンドラーを登録していたりするバックグラウンドアプリの事)
  3. もしキーボードアプリが起動していたら、次に終了されます。
  4. フォアグランドアプリケーションは次に終了されます。
  5. 最後に、 high-priority(高い優先度) や CPU wakelocks を要求しているフォアグランドアプリケーションが最後に終了されます。

: たいていの子プロセスは、フォアグランド動作時は oom_adj 2 で動作します。バックグラウンドの子プロセスは、oom_adj 3 から 6 (を含む)の間で実行されます。ある子プロセスがバックグラウンド時にどの oom_adj を持っているかは、正確にファクタ数(音を鳴らしているのか、キーボードアプリなのか、など)で決まります。

このルールには2つの例外があります。

  • すべての子プロセスが終了してOS を再起動してしまうので、メインプロセスは LMK によって終了される事はありません。メインプロセスは oom_adj が 0 として動作しています。
  • preallocated process と呼ばれる、新しいアプリケーションの起動で速度を上げるためのプロセスを保持しています。このプロセスはメモリ消費量が少ない事と、アプリケーションの起動を速くするため、通常生存したままです。すべてのプロセスを終了した後にメインプロセスを動作させるためのメモリが不足した場合にだけ、このプロセスは終了されます。

低メモリ通知

次のメモリが少なくなったときに利用するメカニズムは低メモリ通知です。 LMK は動作しているメモリが少なくなった事を通知する事が出来る特別な閾値を提供しています。システムアプリケーションと一般的なユーザーアプリケーションは監視サービスから通知される memory-pressure イベントに反応するために条件がくるのを待ち続けています。このイベントは C++ と chrome JS のコードだけに利用でき、直接アプリケーションが利用する事は出来ません。Gecko のコードベースを通じて、我々は利用可能なメモリを空けるためにイベントを利用します。(通常、内部キャッシュ(画像、DNS、sqlite等) を破棄し、再生可能なアセット(WebGL context等) を破棄したり、ガベッジコレクターやサイクルコレクターを実行させたりします)

メモリが少ない状況に直面したら、最初の memory-pressure イベントが low-memory ペイロード付きで送信されるでしょう。定義した時間 (5秒) を経過してもメモリが少ない状況が続いていた場合、他の memory-pressure イベントが、low-memory-ongoing ペイロード付きで発火されます。このペイロードはメモリ不足の状態が継続しているときに利用され、私たちはキャッシュをフラッシュしたり、他のメモリを最少化するための安い方法を望みます。しかし、GC のような処理の重たいアプローチは成功しにくいでしょう。

LMKと低メモリ通知が協働する方法

現在、低メモリーの閾値は バックグラウンドアプリケーションの LMK レベル以上に設定されていますが、ホームスクリーンより低く設定されています。そのため、LMK と低メモリー通知の両方のアクションは、out of memory が端末で発生したときに以下のようにしないといけません。

現在、2つの低メモリ閾値が使われています(ソフトハード閾値)。ソフトレベルはバックグラウンドアプリケーションのLMKレベルより大きく設定されていて、低メモリエラーが始まっているがアプリケーションが停止される前に、メモリ使用を最小化するのに使われます。いっぽうハードレベルは、LMKによってすべてのバックグラウンドアプリケーションが停止された後に、フォアグラウンドアプリケーションを生かし続けるために使われます。ただ1つのカーネルトリガーだけが利用できるため、この2つのレベルは、Geckoが動的にトリガーを調整できることにより、実装されています。端末が低メモリとなった時に、LMKと低メモリ通知の集約されたアクションは次の通り:

  1. すべてのアプリに memory-pressure イベントを通知する
  2. メモリがまだ不足している場合は、最近使用されていない順でバックグラウンドアプリを停止する
  3. メモリがまだ不足している場合は、すべての残っているアプリに memory-pressure イベントを通知する
  4. メモリ不足が継続している場合、5秒間隔で memory-pressure イベントを送信する。しかしGC/CC が反応しないように、実行中にマークする
  5. 認知していたり、高い優先度のバックグラウンドアプリを終了する
  6. もし動作していたらキーボードアプリを終了する
  7. フォアグランドアプリケーションを終了する
  8. フォアグランドアプリケーションの高い優先度のものを終了する
  9. preallocated process を終了する

ドキュメントのタグと貢献者

 このページの貢献者: hamasaki, Uemmra3, mantaroh
 最終更新者: hamasaki,