Androidのアプリケーションは、Java仮想マシン上で動作し、JavaはGCと言語です。ガベージコレクションは、仮想マシンで、STWと呼ばれるものの非常にイメージをするとき(世界を止める);、すなわち、使用されなくなっているオブジェクトを回復するために、仮想マシンが必要なを作るために、すべてのスレッドを停止する必要があります作品。これは、実行時のARTの大幅な向上が、GCのパフォーマンスアプリケーションランタイムの存在となっているが、常に微妙な効果を持っています。あなたが携帯電話のログ入力に目を通す場合は、のようなセクションが表示されます。
12-23 18:46:07.300 28643から28658 /?I /技術:GCは、15442(1400キロバイト)AllocSpaceオブジェクトを解放背景スティッキーコンカレントマークスイープ、8(128キロバイト)LOSオブジェクト、4%フリー、32メガバイト/ 33メガバイトは、GCDaemonスレッドCareAboutPauseTimesで10.356ms総53.023msを一時停止1
12-23 18:46 :12.250 28643から28658 /?I /技術:GCは、28723(1856キロバイト)AllocSpaceオブジェクトを解放背景部分コンカレントマークスイープ、6(92キロバイト)LOSオブジェクト、11%フリー、31メガバイト/ 35メガバイトは、2.380ms一時停止の合計108.502msを GCDaemonスレッドCareAboutPauseTimes 1で
GCは代償:上記のログという事実を反映しています。GC言及したパフォーマンスチューニングに関する多くの記事がありますが、LeakCanary、最終的にはMATに言及し、「メモリリークを避ける」、ガベージコレクションプロセスについて長広舌と同様に原則を過ごすが、戦略は「不必要なオブジェクトを作成しない」よりも何もしなかっただろうツールの使用が上がるなど、私はそれが非常に薄いと弱いと言うことができます - 基本的な要件であるべきなツールを使用することを学ぶ、コードを記述します。
AndroidのNDKは、開発をサポートしていますが、我々は正しい、C ++完全な書き直しですべてのコードを置くことはできませんが?そこで、我々はする方法がありませんGC戦略に影響を与え、それを最小限に抑えるためにGCを作るの?答えはイエスです。原則は、Androidのプロセスメカニズムである-アプリケーションごとにアプリケーション独自のプロセス空間で個別の仮想マシンインスタンスを持って、私たちはかなりの主導権を持っています。
私は簡単な例を挙げてみましょう。(Androidの5.1システムに基づいて、次のコンテンツは、原則の全てとコードは、システムの他のバージョンでは、さらにROM上で動作することが保証されていません)
すべてのプロセスは、Appは、受精卵のプロセスフォークから来ている、プロセス空間の受精卵のプロセスを共有するための書き込みメカニズムのAndroidコピー上のアプリケーションを使用して子プロセス;とAndroidランタイムAndroidのシステム起動は、プロセスが受精卵を作成された仮想マシンを作成します完了しました。ガベージコレクションは、それゆえ、我々は起動プロセス受精卵プロセスについて話し始めると、仮想マシンの一部です。
私たちは、Androidシステムは、Linuxカーネル、およびLinuxシステムに基づいており、すべてのプロセスはinitプロセスのプロセスの子孫である、接合体のプロセスは例外ではない、知っている、それはinitプロセスによって作成され、システムの起動のプロセスです。システムの起動スクリプトシステム/コア/ ROOTDIR / init.rcファイルでは、我々は、受精卵のプロセスを開始するには、スクリプトコマンドを参照してくださいすることができます:
サービス受精卵/システム/ binに/ app_process -Xzygote /システム/ binに-zygote -start・システム・サーバー
実装/システム/ binに介してその初期化処理/ app_process接合子プロセスを作成する実行可能ファイル、app_processソースコードが表示され、ここで、そのような言葉は、最後の主要な機能です。
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args);
} else if (className) {
決勝への呼び出しAndroidRuntime.cppstart
機能、およびこの機能は、最も重要なステップは、仮想マシンを起動することです:
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
return;
}
この機能はかなり長いですが、このようなヒープサイズなどとして、仮想マシンの起動の分析パラメータ、ある; largeHeapを探るこれらのパラメータの説明を行うには、いくつかの重要なパラメータについては、この記事では、仮想マシンのために非常に重要である、我々は後で見ます。パラメータを解析した後、最終的に通話を終了しJNI_CreateJavaVM
、実際にJava仮想マシンを作成します。このインタフェースは、のDalvikは、従来と大幅に切り替えることができ、3つのAndroidの仮想マシンのインタフェースによって定義されます。これは、特に今であるjni_internal.cc:直接Androidのランタイムを作成した仮想マシンの関連するパラメータを取得するには、この関数の後のJNI_CreateJavaVM。
if (!Runtime::Create(options, ignore_unrecognized)) {
return JNI_ERR;
}
ヒープのコンストラクタは、あなたが戦略を調整したい場合は、GC、GCのために重大な影響を与えるパラメータの束を受け入れ、GC、アプリが出て作成されたヒープに関連付けられている、非常に複雑な作成するためのランタイムここから始まる、それはより信頼性が高くなります。
heap_ = new gc::Heap(options->heap_initial_size_,
options->heap_growth_limit_,
options->heap_min_free_,
options->heap_max_free_,
options->heap_target_utilization_,
options->foreground_heap_growth_multiplier_,
options->heap_maximum_size_,
// ...
heap_initialどのサイズのヒープの初期サイズは、heap_growth 制限が上限ヒープの成長、heap_minで無料などとheap_maxは、フリーとは?詳細な使用方法を参照アンドロイドART GCの分析GrowForUtilizationをメモリ断片化ヒープを低減する、ヒープの効率を確保するために、単にAndroidシステムを、GC後の各実行は、いくつかのメモリヒープサイズが調整されます再利用します。たとえば、あなたが絵のページの多くは、100Mメモリに適用されるこの時間、あなたはそれが100Mの自然回収されたこのページを離れるとき、空きメモリとなって入力しますが、無駄を防ぐためにシステムを入れません空きメモリの100Mは、あなたはすべてを残すが、調整を行うこと。特定のどのくらいの、その後の調整heap_min_free_
、heap_max_free_
同様にheap_target_utilization_
関連します。
ここで、原理は説明の一部は終わったされています。プロセスのほかに支障はありません、少し複雑です。その後ヒープは、私たちのパフォーマンスの最適化から始まる、それは何を問題ではありませんか?
スタートアップのAndroidアプリの中には、時間をかけてプロセスメモリが上昇して、ヒープの初期サイズは8Mであると仮定し、30Mの起動時にメモリピークを取る、ブートプロセスに、一時的なオブジェクトの数が多いとともに、作成された、彼らはChaosheng Xiが、死んですぐに回収されます。
上に示したように、これはメモリ使用量のApp起動中に一定の時間があり、私たちは短い線をたくさん見てきた、専門用語は、ジッタメモリと呼ばれ、その理由は、我々はまた、非常に明確である - 作成された一時オブジェクトの多くがあります。どのように解決するには?一部の人々は、一時的な大量のオブジェクトを作成しない、と言います。私はすべての真実を知っているが、できません。多くの大規模なアプリケーションの場合、プロセスは非常に複雑で開始し、多くの操作は単純に削除ドロップすることはできません。そこで問題は、30Mは非常に多くありませんが、なぜシステムがそうパニックですが、また回復したメモリを落としておく必要がありますか?
あなたの母と呼ばれる冷たいあなたは寒さだと思うがあります。ガベージコレクションは回復に行く前にゴミがあると言うことが、限り、あなたが感じるように、システムがガベージする必要があることではありません。
まあ、それなしで持続的な成長を維持するために、ブートプロセスのヒープGC中に許可することはできませんか?結局のところ、30Mとは、任意のOOMが発生することはありません。どのようなシステムがそれをしない原因は?その答えは、その空きメモリです。例えば、開始ヒープ8Mが24Mに成長するブートプロセスのヒープの進展と、そこにある。この時間は、GCを実行し、失われた8Mのメモリを回復、またヒープ16Mに戻って、我々は、空きメモリの8Mを持っています。システムは、若い男を言うだろう、あなたはそんなに空きメモリを取っていることをしているのですか?ママはあなたが保つために、あなたは自由2Mのメモリをある残されています。しかし、明確にヒープメモリのAppの使用はすぐに18M以上になりますので、彼は記憶を完了するために、順調なスタートになるまで何度も何度も、GCヒープサイズ調整のシリーズを開始しました。これまでのところ、我々は非常に明確な結論となっています。
我々はheap_minを調整することができた場合は無料とし、heap_max 無料など、大幅にGCのプロセスに影響を与えることができるようになります
これら2つのパラメータ、それのサイズを調整するには?ヒープポインタは、あなたが直接メモリを変更することができ、これら2つのパラメータのオフセットを見つけ、オブジェクトを取得するには、ここでC ++メモリレイアウトの知識を少し必要があります。オブジェクトにヒープポインタを取得する方法については、ソースコードだけ内側に答えを見つけるために。ここで私は、最終的な実装コードを与えます:
void modifyHeap(unsigned size) {
// JavaVMExt指针 可以从JNI_OnLoad中拿到
JavaVMExt * vmExt = (JavaVMExt *)g_javaVM;
if (vmExt->runtime == NULL) {
return;
}
char* runtime_ptr = (char*) vmExt->runtime;
void** heap_pp = (void**)(runtime_ptr + 188);
char* c_heap = (char*) (*heap_pp);
char* min_free_offset = c_heap + 532;
char* max_free_offset = min_free_offset + 4;
char* target_utilization_offset = max_free_offset + 4;
size_t* min_free_ = (size_t*) min_free_offset;
size_t* max_free_ = (size_t*) max_free_offset;
*min_free_ = 1024 * 1024 * 2;
*max_free_ = 1024 * 1024 * 8;
}
以下の起動プロセスのメモリ使用量を変更した後、私たちは私たちの目的が達成されたことを確認できます。
ところで、上記のコードは、プレゼンテーションの役割を果たし、移植性と互換性のいずれかを考慮していません。本当に利用されるように物理的な作品である置く:まず、我々は、メンバ変数が異なるバージョンでは異なる場合がありますオフセットのAndroidのクラスの特定のバージョンのメモリレイアウトに依存している;第二に、分無料などとmax 無料ように固有の調整携帯電話の物理メモリ、メモリ、携帯電話のアプリケーションを使用して構成された他の要因の中でも、初期ヒープサイズ、に関連するどのように密接に、パラメータを適切に調整するには、ある程度の時間を要し、Androidのモデルはあまりここにいくつかのヒントを必要としています。
不知道上面这个例子有木有让你感受到深入系统底层,那种呼风唤雨无所不能的快感?可能很多人觉得我们都是写写if else而已,调节面改动画写业务已经够了;但我想说明的是,深入学习系统原理是非常有好处的,它可以赋予你在应用层永远无法拥有的能力。
自己是从事了七年开发的Android工程师,不少人私下问我,2019年Android进阶该怎么学,方法有没有?
没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助那些想进阶提升Android开发,却又不知道怎么进阶学习的朋友。【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。