ほとんどの場合、どの Android アプリケーションも独自の Linux プロセスで動作します。このプロセスは、アプリケーションのコードの一部を実行する必要があるときに作成され、プロセスが不要になり、かつシステムが他のアプリケーションで使用するためにメモリを回収する必要があるときまで残ります。
Android の基本的な特徴のうち、一般的ではないものとして、アプリケーション プロセスの存続期間がアプリケーションによって直接制御されないということがあります。存続期間は、システムによって、実行中であることが認識されているアプリケーション、ユーザーにとっての重要度、システム全体での空きメモリ量の組み合わせから決定されます。
アプリケーション デベロッパーにとっては、さまざまなアプリケーション コンポーネント(特に、Activity
、Service
、BroadcastReceiver
)がアプリケーションのプロセスの存続期間にどのように影響するかを理解することが重要です。これらのコンポーネントを正しく使用しないと、重要な作業を行っている間にシステムがアプリケーション プロセスを終了させる場合があります。
プロセスのライフサイクルに関連する不具合としてよくあるのは、BroadcastReceiver
が BroadcastReceiver.onReceive()
メソッド内でインテントを受け取る際にスレッドを開始し、関数から戻ってしまう場合です。関数から戻ると、BroadcastReceiver が無効になったため、ホストプロセスが不要になった(プロセス中で他のアプリケーション コンポーネントが有効でない場合)とシステムにみなされます。したがって、システムはメモリを再請求するためにいつでもプロセスを終了でき、プロセスで実行中の生成済みスレッドを終了させます。この問題への対応策は、BroadcastReceiver の JobService
のスケジュールを設定するのが一般的です。そうすることで、プロセス内に有効な実行中処理が残っていることをシステムに認識させられます。
メモリが不足している場合に終了させるプロセスを決定するために、Android は実行中のコンポーネントとその状態に基づいて、各プロセスの重要度を階層中に位置付けます。プロセスには、次のタイプがあります(重要度の高い順)。
- フォアグラウンド プロセス: ユーザーが現在行っている作業に必要なプロセスです。さまざまなアプリケーション コンポーネントが、さまざまな方法で、そのプロセスをフォアグラウンドとみなされるようにします。次のいずれかの条件が満たされている場合、プロセスはフォアグラウンドであるとみなされます。
- ユーザーが操作している画面の上部で
Activity
が動作している(onResume()
メソッドが呼び出されている)。 - 現在実行中の
BroadcastReceiver
がある(BroadcastReceiver.onReceive()
メソッドが実行中)。 Service.onCreate()
、Service.onStart()
、Service.onDestroy()
のいずれかのコールバックのコードを実行しているService
がある。
- ユーザーが操作している画面の上部で
- 表示プロセス: 処理がユーザーに認識されているプロセスです。そのため、終了させるとユーザー エクスペリエンスが大きく損なわれます。以下の条件に該当する場合、表示プロセスとみなされます。
- フォアグラウンドではないが、画面上でユーザーに表示されている
Activity
を実行している(onPause()
メソッドが呼び出されている)。たとえば、フォアグラウンドのアクティビティがダイアログとして表示されており、以前のアクティビティの背後に表示することが許可されている場合に起こります。 Service.startForeground()
を使って、フォアグラウンド サービスとして実行しているService
がある(サービスをユーザーが認識しているか、実質的に見えているものとして扱うように要求します)。- ライブ壁紙やインプット メソッド サービスなど、ユーザーに認識されている特定の機能のためにシステムが使用しているサービスをホストしている。
実行中のプロセスの数は、フォアグラウンド プロセスほど制限されていませんが、ある程度管理されています。これらのプロセスは、非常に重要であるとみなされ、すべてのフォアグラウンド プロセスを実行し続けるために必要となる場合を除いて、終了されることはありません。
- フォアグラウンドではないが、画面上でユーザーに表示されている
- サービス プロセス:
startService()
メソッドで開始されたService
を保持しているプロセスです。これらのプロセスはユーザーに直接表示されることはありませんが、バックグラウンドでのネットワーク データのアップロードやダウンロードなど、ユーザーが注意を向けていることの多い処理を行います。そのため、フォアグラウンド プロセスや表示プロセスを保持するのに十分なメモリがある限りは、これらのプロセスを実行したままにします。長時間実行されるサービス(30 分以上など)は重要度が下げられ、次に説明するキャッシュ済み LRU リストにプロセスが含められるようになります。これにより、メモリリークなどの問題がある長時間実行中のサービスが RAM を大量に消費して、キャッシュ済みプロセスが効果的に使用できなくなることを防ぎます。
- キャッシュ済みプロセス: その時点では必要ではなく、他の場所でメモリが必要な場合には自由に終了させることができるプロセスです。これは、正常に動作するシステムでは、唯一メモリ管理に関連するプロセスです。正常に実行されているシステムには、アプリケーション間の切り替えを効率的に行うため、常に利用可能なキャッシュ済みプロセスが複数あり、通常は必要に応じて最も古いものが終了させられます。すべてのキャッシュ済みプロセスを終了させ、さらにサービス プロセスの終了を始める必要があるのは、非常に重大な(好ましくない)状況が生じた場合のみです。
これらのプロセスは、多くの場合、ユーザーに表示されていない(
onStop()
メソッドが呼び出されて戻った)Activity
インスタンスを 1 つまたは複数保持します。アクティビティのライフサイクルを適切に実装していれば(詳細はActivity
をご覧ください)、システムがそのようなプロセスが終了しても、そのアプリに戻るときにユーザー エクスペリエンスが損なわれることはなく、関連付けられたアクティビティが新しいプロセスで再作成されたときに、以前に保存された状態を復元できます。これらのプロセスは擬似 LRU リストに保存されます。このリストの最後のプロセスが最初に終了され、メモリが再請求されます。このリストでの順序付けの正確なポリシーは、プラットフォームの実装の詳細として扱われますが、一般的に、より有用なプロセス(ユーザーのホーム アプリケーションをホストしているプロセスや最後に表示したアクティビティなど)を他の種類のプロセスより先に保持します。プロセスを終了させるポリシーとして、プロセス数のハードリミット、プロセスをキャッシュに保持できる時間の制限など、他のポリシーも適用できます。
このようなプロセスはシステム内にわずかしか存在せず、空きメモリが非常に少なくプロセスを実行し続けることができない場合にのみ、最後の手段として終了させられます。一般に、この時点でデバイスはメモリ ページング状態になっているため、この動作はユーザー インターフェースの応答性を維持するために必要です。
プロセスの重要度付けの方法を決める際には、プロセスで現在有効なすべてのコンポーネントの中で最も重要なレベルに基づいて決定します。各コンポーネントがプロセスのライフサイクル全体にどのように貢献しているかについて詳しくは、Activity
、Service
、BroadcastReceiver
のドキュメントをご覧ください。各クラスのドキュメントでは、それらがアプリケーションのライフサイクル全体にどのように影響するかを詳しく説明しています。
プロセスの他の依存関係に基づいて、プロセスの優先度を上げることもできます。たとえば、プロセス A が、プロセス B の Context.BIND_AUTO_CREATE
フラグの付いた Service
にバインドされているか、プロセス B の ContentProvider
を使用している場合、プロセス B の重要度は最低でもプロセス A と同じになります。