JVMを学習した後、モバイルデバイスで実行されている仮想マシンDalvikとARTについて学習します。DVMとARTを学習した後、図面を最適化できます。
DalvikとARTも非常に大規模なシステムです。Androidアプリケーション開発では、基本的な原則を習得し、ログを確認するだけで済みます。
この記事は基本的なものだけを紹介しています。詳しく知りたい場合は、専門書を読む必要があります。
ARTはAndroid 4.4で生まれ、DVMとARTは4.4バージョンで置き換えることができます。Android5.0以降、Androidはデフォルトで仮想マシンをARTとして実行します。この時点で、DVMは歴史的な段階を終了します。
2020年、世界中のAndroidユーザーの間で、5.0以上のバージョンが87〜90%を占めています。DVMが更新されていなくても、DVMを学ぶ必要があります。ARTに共通することはたくさんあります。また、DVMの特性と欠点を理解し、ARTが新しい低レベルランタイムライブラリになる理由を探っていくと、さらに便利です。
1. Dalvik仮想マシン
Dalvik Virtual Machine(DVM)は、GoogleがAndroidプラットフォーム専用に開発した仮想マシンであり、Androidランタイムライブラリで実行されます。
1.1 DVMとJVMの違い
DVMはJVMですか?答えは-----いいえ!なんで?---- DVMはJVM仕様に従っていないためです。
それらの違いをリストすることで、DVMの特性を知ることができます。
1.異なるアーキテクチャーベースの
JVMはスタックベースです。つまり、JVMはデータを読み書きするためにスタックに移動する必要があり、さらに多くの指示が必要です。PCプラットフォームは性能が良いのであまり感じません。ただし、パフォーマンスが制限されているモバイルデバイスには、あまり適していません。
DVMはレジスタに基づいています。スタックベースのメカニズムのようにデータをコピーするときに使用される大量のスタックアクセス命令を必要とせず、その命令はよりコンパクトで簡潔です。
ただし、ディスプレイはオペランドを指定するため、レジスタベースの命令はベースステーションベースの命令よりも大きくなりますが、命令の数が減少するため、コードの総数はそれほど増加しません。
2.別のバイトコードを実行し
、我々はJVMが実行している知っている.class
JVMが直接特定し、した後、ファイルを。
DVMの使用するDXツールを全てます.class
にファイルを変換.dex
しますDVMから、ファイル、および.dex
命令とデータファイルを読み込みます。実行順序は.java->。Class->。Dexです。
では、なぜもっと多くのことをしたいのですか?
これは、のJava .jar
の数含まれているファイル.class
JVMによって、このロードされたファイル、.jar
ロードするようになりますすべてが時間、.class
ファイルを。特に大規模で大規模なプロジェクトの場合、このようなJVMの読み込みは非常に遅くなるため、メモリファーストのモバイルデバイスには適していません。
だから.apk
1つだけあるファイル.dex
のファイルは、.dex
ファイルがすべて含まれています.class
ファイル:DEXツールを取り除くになる.class
すべての冗長な情報、およびすべてを入れて.class
、単一に.dex
ファイル、検索スピードクラススピードアップするためにI / O操作を削減します。
3.
DVMを使用すると、限られたメモリで複数のプロセスを同時に実行できます DVMは、優先メモリで複数のプロセスを同時に実行できるように最適化されています。
Androidの各アプリケーションは DVMインスタンスで実行され、各DVMインスタンスは独立したプロセスコントロールで実行されます。独立したプロセスは、仮想マシンがクラッシュしたときにすべてのプログラムが閉じられるのを防ぎます。
JVMでは、プロセスはJVMです。
4.
DVMはZygote によって作成および初期化されます ZygoteはDVMプロセスであり、DVMインスタンスの作成および初期化にも使用されます。
システムがアプリケーションを作成する必要があるときはいつでも、Zygoteは自身をforkして、アプリケーションを実行するためのDVMインスタンスをすばやく作成して初期化します。
一部の読み取り専用システムライブラリでは、すべてのDVMインスタンスがメモリ領域をZygoteと共有し、メモリのオーバーヘッドを節約します。
5.
DVMには共有メカニズムがあります DVMにはプリロード共有メカニズムがあり、さまざまなアプリケーションが実行時に同じクラスをより高い効率で共有できます。
ただし、JVMメカニズムにはそのような共有メカニズムはなく、パッケージ化されたプログラムは互いに独立しています。
パッケージで同じクラスを使用している場合でも、ランタイムは個別に読み込まれて実行されるため、共有できません。
6. DVMは初期の段階ではJITコンパイラを使用していませんでした
。JVMはJIT(ジャストインタイム)コンパイラを使用していましたが、DVMは初期の段階ではJITコンパイラを使用していませんでした。
初期のDVMがコードを実行するたびに、インタープリターを介してdexコードをマシンコードにコンパイルし、それをシステムに渡す必要があり、あまり効率的ではありませんでした。
この問題を解決するために、DVMはAndroid 2.2でJITの使用を開始しました。これにより、複数回実行されたコード(ホットスポットコード)がコンパイルされ、比較的合理化されたローカルマシンコードが生成されるため、次回同じロジックが実行されるときに、コンパイルが使用されます。毎回コンパイルする必要があるローカルマシンコードの代わり。
アプリケーションを再実行するたびにコンパイル作業をやり直す必要があるため、アプリケーションを再度開くたびにJITコンパイルが必要になることに注意してください。
1.2 DVMアーキテクチャ
DVMのソースコードはdalvik /ディレクトリの下にあり、ディレクトリの説明は次のとおりです。
- Android.mk
は、仮想マシンによってコンパイルされたmakefileです - VMに
は、仮想マシンの初期化やメモリ管理コードなど、ほとんどの仮想マシンコードが含まれています
JavaバイトコードをDVMマシンコードに変換するdx 生成ツール- ヒット
はスタック情報/オブジェクト情報を表示するツールを生成します - libdex
は、ホストとデバイスがdexファイルを処理するためのライブラリを生成します - Dexopt
はdex最適化ツールを生成します - Dexdump
によって生成された.dex
ファイルの逆コンパイル表示ツール。主に、コンパイルされたコードの正確さと構造を確認するために使用されます - dexlist
このディレクトリは、dexファイル内のすべてのクラスを表示するメソッドを生成するためのツールです - dexgen
.dex
ファイルコードジェネレータプロジェクト - docs
DVM関連のヘルプドキュメント
コンパイルと操作に関連するいくつかのツール- MODULE_LICENSE_APACHE2
APACHE2著作権通知ファイル - 通知
仮想マシンのソースコードの著作権情報ファイル
どちらlibdex
にコンパイルされますlibdex.a
DEXツールとして、静的ライブラリ。DVMアーキテクチャを以下に示します。
1.3 DVMの実行時ヒープ
DVMのランタイムヒープは、GCにマークアンドスイープアルゴリズムを使用します。
2つのスペースと複数の補助データ構造で構成されています。2つのスペースは、Zygote Space(Zygote Heap)とAllocation Space(Active Heap)です。以下は、それらの説明です。
- Zygote Spaceは
、Zygoteプロセスの起動時にプリロードおよび作成されたさまざまなオブジェクトの管理に使用されます。GCはZygote Spaceではトリガーされません。
Zygote Spaceは、Zygoteプロセスとアプリケーションプロセスの間で共有されます。Zygoteプロセスフォークの最初の子プロセスの前に、Zygote Spaceは2つの部分に分割されます。使用されたヒープの元の部分は引き続きZygote Spaceと呼ばれ、ヒープの未使用部分はAllocation Spaceと呼ばれます。
割り当てスペースの後のすべてのオブジェクトは、割り当てスペースに割り当てられて解放されます。割り当てスペースはプロセス間で共有されず、各プロセスには独自のコピーがあります。- Card Tableは
DVM Concurrent GCに使用されます。初めてガベージマーキングが実行されると、ガベージ情報が記録されます - ヒープビットマップに
は2つのヒープビットマップがあり、1つは最後のGCライブオブジェクトの記録に使用され、もう1つはこのGCライブオブジェクトの記録に使用されます - Mark Stack
DVMのランタイムスタックは、GCのマークアンドスイープアルゴリズムを使用します。MarkStackは、GCのマーキングフェーズ中に使用され、生き残ったオブジェクトをトラバースするために使用されます。
1.4 DVMのGCログ
DVMおよびARTのGCログは、JVMのログとは大きく異なります。
DVMの各ガベージコレクションはGCログをlogcatに出力します。具体的な形式は次のとおりです。
D/dalvikv: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>
DVMログには5つの情報が含まれていることがわかります。その中には、さまざまなタイプのGC理由があり、ここで個別に紹介します。
1. GC
GCの原因理由はGCの原因であり、次のようなものがあります。
- GC_CONCURRENT:ヒープがいっぱいになり始めると、同時GCがメモリを解放できます
- GC_FOR_MALLOC:メモリヒープがいっぱいになると、アプリはGCが原因のメモリを割り当てようとし、システムはアプリを停止してメモリを再利用する必要があります。
- GC_HPROF_DUMP_HEAP:ヒープメモリを分析するためのHPROFファイルの作成を要求したときに表示されるGC
- GC_EXPLITCIT:表示されたGC。たとえば電話する
System.gc()
- GC_EXTERNAL_ALLOC:APIが10以下のGCにのみ適用され、外部に割り当てられたメモリに使用されます
2.その他の情報
- Amout_freed
このGCによって解放されたメモリのサイズ - Heap_stats
ヒープ空きメモリの割合:(使用済みメモリ)/(合計ヒープメモリ) - External_memory_stats
API <= 10のメモリ割り当て(割り当てられたメモリ)/(しきい値が原因のGC) - 一時停止時間
一時停止時間。ヒープが大きいほど、一時停止時間が長くなります。同時休止時間には、ガベージコレクションの開始時とガベージコレクションの終了時の2つの休止時間が表示されます。
3.分析例
logcatのGCを例にとります。
D/dalvikvm: GC_CONCURRENT freed 2012k, 63% free 3213K/9291K, external 4501K/5161K, paused 2ms+2ms
意味:GCの原因はGC_CONCURRENTです。このGCによって解放されたメモリは2012KB、ヒープ内の空きメモリの割合は63%、使用済みメモリは3213K、ヒープの合計メモリは9291K、一時停止の合計時間は4msです
2.ART仮想マシン
ARTはAndroid 5.0のDVMを完全に置き換えました
2.1 ARTとDVMの違い
- アプリケーションがDVMで実行されるたびに、JITを介してバイトコードをマシンコードにコンパイルする必要があります。これにより、アプリケーションの動作効率が低下します。システムでは、アプリケーションをインストールするときに、システムが
AOT(ahead of time compilation,预编译)
バイトコードの事前コンパイルを1回実行します。マシンコードにコンパイルされてローカルに保存されるため、プログラムを実行するたびにアプリケーションがコンパイルを実行する必要がなく、実行効率が大幅に向上します。デバイスの消費電力も削減されます。
AOTプリロードの使用には、主に2つの欠点があります。1つ目は
、AOTがアプリケーション側のインストール時間を長くすることです。2つ
目は、バイトコードがマシンコードにプリコンパイルされ、マシンコードにさらに多くのストレージスペースが必要です(ここに時間のスペースがあります)。 )
上記の欠点を解決するために、Android 7.0バージョンのJITにARTが追加されました。AOTの補足として、アプリケーションのインストール時にすべてのバイトコードがマシンコードにコンパイルされるわけではありませんが、ホットスポットは動作しています。コードはマシンコードにコンパイルされるため、アプリケーションのインストール時間が短縮され、ストレージスペースが節約されます。 - DVMは32ビットCPU用に設計されており、ARTは64ビットをサポートし、32ビットCPUと互換性があります。これは、DVMが排除された主な理由の1つです。
- ARTは、GCをより頻繁に実行するなどのガベージコレクションメカニズムを改善し、GCの一時停止を2つから1つに減らしました。
- ARTのランタイムヒープスペースの分割はDVMとは異なります
2.2 ARTのランタイムヒープ
DVMのGCとは異なり、ARTはさまざまなガベージコレクションスキームを使用します。各スキームは異なるガベージコレクターを実行します。デフォルトはCMS(Concurrent Mark-Sweep)スキームで、主にスティッキー- CMSと部分CMS、異なるCMSスキームによると、ARTのランタイムヒープ制御も異なる方法で分割されます。デフォルトは4つのスペースと複数の補助データ構造で構成されます。4つのスペースは、Zygote Space、Allocation Space、Image Space、およびLarge Object Spaceです。最初の2つはDVMと同じです。
- Image Spaceは、
いくつかのプリロードされたクラスを格納するために使用されます - ラージオブジェクトスペースは、
いくつかのラージオブジェクトを割り当てるために使用されます(デフォルトサイズは12KB)
その中で、Zygote SpaceとImage Spaceはプロセス間で共有されるスペースです。
これらの4つのスペースに加えて、ARTのJavaヒープには、2つのModユニオンテーブル、カードテーブル、2つのヒープビットマップ、2つのオブジェクトマップ、および3つのオブジェクトスタックも含まれています。
2.3 ARTのGCログ
ARTのGCログとDVMの違いは、ART は、アクティブに要求されているガベージコレクションイベント、またはGCの速度が遅いと考えられる場合にのみ、GCログを出力することです。
遅いGC速度は、GCの一時停止時間が5ミリ秒を超えるか、GCの継続時間が100ミリ秒を超えることを意味します。アプリが一時停止状態になっていない場合、GCが遅いとは見なされません。
ARTのGCログの具体的な形式は次のとおりです。
I/art: <GC_REASON> <GC_NAME> <Objects_freed>(<Size_freed>) AllocSpace Objects,
<Large_objects_freed>(<Large_object_suze_freed>) <Heap_stats> Losobjects,
<Pause_time(s)>
1. GCの原因
ARTがDMVよりもGCを引き起こす
- 同時
並行GCはアプリスレッドを一時停止しません。GCはバックグラウンドスレッドで実行され、メモリ割り当てを整理しません - Alloc
メモリがいっぱいになると、アプリはGCによってメモリを割り当てようとしますが、このGCはメモリを割り当てているスレッドで発生します - 明示的な
アプリは、呼び出しなどのガベージコレクションのリクエストを表示しますSystem.gc()
。
しかし、呼び出し側のGCを表示したくないので、GCを信頼する必要があります。示されているコールGCは、スレッドの割り当てを防ぎ、不必要にCPUサイクルを浪費します。GCを明示的に要求すると、他のスレッドがプリエンプトされる場合、ジャンクにつながる可能性があります(同じフレームでアプリが何度も描画する) - NativeAlloc
ネイティブメモリの割り当て(ビットマップやRenderScriptのオブジェクトの割り当てなど)。これにより、ネイティブメモリが圧迫され、GCがトリガーされます。 - CollectorTransition
は、実行時にGCを切り替えることによって引き起こされるヒープ変換によって引き起こされます。コレクターの遷移には、フリーリストスペースからコリジョンポインタースペースへのすべてのオブジェクトのコピーが含まれます。現在、コレクターの遷移は、次の状況で発生します。メモリの少ないデバイスで、アプリがプロセスの状態を顕著な一時停止から一時停止に変更する認識可能な一時停止状態 - HomogeneousSpaceCompact
同種スペース圧縮とは、圧縮された空きリストスペースへのスペースリストを指します。通常、アプリが一時停止プロセスの状態に移行したときに発生します。これの主な理由は、メモリ使用量を減らし、ヒープメモリをデフラグすることです。 - DisableMovingGc
は実際にはGCをトリガーする理由ではありません。同時ヒープ圧縮が発生すると、GetPrimitiveArrayCritical
コレクションはその使用のためにブロックされます。一般にGetPrimitiveArrayCritical
、コレクターの移動に制限があるため、使用しないことを強くお勧めします - HeapTrim
はGCの原因ではありません。コレクションは、ヒープメモリが整理されるまでブロックされます。
2.ガベージコレクター名
GC_NAMEは、ガベージコレクター名を指します。
- 並行マークスイープ(CMS)
CMSコレクターは、最短の収集休止時間を取得することを目的としたコレクターです。
マークスイープアルゴリズムを使用します。完全なヒープガベージ情報であり、イメージスペース以外のすべてのスペースを解放できます。
完全なガベージコレクターの並行部分マークスイープパーツ。イメージスペースとZygoteスペースを除くすべてのスペースを解放できます。
世代別ガベージコレクションのアイデアに基づく並行スティッキーマークスイープスティッキーコレクターは、最後のGC以降に割り当てられたオブジェクトのみを解放できます。
このガベージコレクターは高速で一時停止時間が短いため、完全または部分的なガベージコレクターよりも頻繁にスキャンします。- Marksweep +セミスペース
非並行GC、ヒープ変換および同種空間圧縮のためのコピーGC
3.その他の情報
- 解放された
オブジェクトこのGCによって非ラージオブジェクトスペースから回復されたオブジェクトの数 - Size_freed
このGCによって非ラージオブジェクトスペースから回復されたバイト数 - 解放
されたラージオブジェクトこのGCによってラージオブジェクトスペースから回復されたオブジェクトの数 - 解放されたラージオブジェクトサイズ
このGCによってラージオブジェクトスペースから回復されたバイト数 - ヒープ統計ヒープ内
の空きメモリの割合、つまり(使用メモリ)/(ヒープの合計メモリ) - 一時停止時間と
一時停止時間。一時停止時間は、GCの実行中に変更されたオブジェクト参照の数に比例します。
現在、ARTのCMSコレクターは一度だけ停止されており、GCの終わり近くに現れます。モバイルガベージコレクターは長期間停止され、ほとんどのガベージコレクション中に表示され続けます。
4.ケース分析
I/art: Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 21(416KB) LOS objects,
33% free, 25MB/38MB, paused 1.230ms total 67.1ms
これは、このGCの理由が明示的で、コレクターがCMS、解放されたオブジェクトの数が104710、解放されたバイト数が7MB、解放された大きなオブジェクトの数が21 416kであり、ヒープの空きメモリが33%を占めていることを意味します。合計メモリは38MB、25MBが使用され、一時停止時間は1.23ms、GC合計時間は67.1msです。
AndroidStudioでは、Logcatを開いて「gc」をフィルタリングすることにより、ログを表示できます。
3.まとめ
上記の2つのセクションでは、DVMとARTの特性、それらの構造、ランタイムヒープ、GCメカニズム、およびGCログの表示方法について説明します。
DVMとARTの違い、およびこれら2つの仮想マシンとJVMの違いも確認できます。
さらに、DVMとARTがどのように生成されるかを理解する必要があるかもしれません。関係するソースコードはZygoteに関連しており、Zygoteに関する私の知識は十分に明確ではないので、この2か月で、具体的に時間を費やしました。接合体に関する補足知識。