Virtual Machine Tuning performance optimization of Android

Android App runs on the Java Virtual Machine, and Java is a language with GC. When garbage collection in a virtual machine, do a very image of the thing called the STW (stop the world); that is to say, in order to recover those objects no longer in use, the virtual machine must stop all the threads to make the necessary jobs. Although this has been a great improvement in the run time ART, but the presence of GC performance App runtime always have a subtle effect. If you look through the phone log input, you will see a section that looks like:

12-23 18:46:07.300 28643-28658/? I/art: Background sticky concurrent mark sweep GC freed 15442(1400KB) AllocSpace objects, 8(128KB) LOS objects, 4% free, 32MB/33MB, paused 10.356ms total 53.023ms at GCDaemon thread CareAboutPauseTimes 1
12-23 18:46:12.250 28643-28658/? I/art: Background partial concurrent mark sweep GC freed 28723(1856KB) AllocSpace objects, 6(92KB) LOS objects, 11% free, 31MB/35MB, paused 2.380ms total 108.502ms at GCDaemon thread CareAboutPauseTimes 1

The above reflects the fact that the log: GC comes at a price. There are many articles about performance tuning mentioned GC, will spend a tirade about the garbage collection process as well as the principle, but the strategy did nothing more than "not to create unnecessary objects", "avoid memory leaks" final mentions MAT, LeakCanary such as the use of tools go up; I can only say that it is very pale and weak - write code, learn to use the tools should be the basic requirement.

Although the Android NDK also support the development, but we can not put all the code in C ++ full rewrite, right? So, we have no way to affect the GC strategy , making the GC to minimize it? The answer is yes. The principle is the process mechanism of Android - App each has a separate virtual machine instances in the App own process space, we have considerable initiative.

Let me give a simple example. (The following content based on Android 5.1 system, all of the principles and the code is not guaranteed to work in other versions of the system and even on ROM)

All processes are App comes from Zygote process fork, the child process using App on Android copy on write mechanism for sharing the process space Zygote process; and creating a virtual machine in which the Android runtime Android system startup, when the process has been created Zygote finished. Garbage collection is part of a virtual machine, therefore, we start talking about the startup process Zygote process.

We know, Android system is based on the Linux kernel, and the Linux system, all processes are descendants of init process process, Zygote process is no exception, it is in the process of system startup, created by the init process. In the system startup script system / core / rootdir / init.rc file, we can see the script command to start the process of Zygote:

service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server

That init process through the implementation / system / bin / app_process the executable file to create a zygote process; app_process source code is visible here ; there is such a word in the last main functions:

if (zygote) {
 runtime.start("com.android.internal.os.ZygoteInit", args);
} else if (className) {

Final call to AndroidRuntime.cpp the startfunction, and this function is the most important step is to start the virtual machine:

JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
 return;
}

This function is rather long, but are analytical parameters of the virtual machine starts, such as heap size etc; explore largeHeap this article for some important parameters to do a description of these parameters is very important for the virtual machine, we will see later. After parsing the parameters is completed, the final call JNI_CreateJavaVMto actually create Java Virtual Machine. This interface is defined by three Android virtual machine interfaces that, dalvik can switch to a large extent with the related art. It is in particular now jni_internal.cc ; JNI_CreateJavaVM after this function to get the relevant parameters of the virtual machine directly created Android runtime:

if (!Runtime::Create(options, ignore_unrecognized)) {
 return JNI_ERR;
}

Runtime to create very complex, which is associated with GC, heap App was created out; Heap constructor accepts a bunch of parameters that have a significant impact for GC, GC if you want to adjust the strategy, starting from here, it is more reliable.

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_,
// ...

Which heap_initial size is the initial size of the heap, heap_growth limit is the maximum limit heap growth, heap_min as Free and heap_max as Free What is it? See detailed usage analysis GrowForUtilization of the Android ART GC is simply, Android system in order to ensure the efficiency of the heap, reducing memory fragmentation heap; each execution after the GC to reclaim some memory heap size will be adjusted. For example, you enter the picture a lot of pages, this time applied for a 100M memory, when you leave this page when it was recovered 100M nature, become free memory; but the system in order to prevent waste, not put 100M of free memory you leave all, but to do an adjustment. The specific adjustments to how much, and then heap_min_free_, heap_max_free_as well as heap_target_utilization_related.

Here, the principle has been part of the explanation is over; in addition to the process is slightly more complicated, there is no difficulty. Then the heap, starting with our performance optimization what does it matter?

During startup Android App, the process memory over time is rising; assume heap initial size is 8M, take up memory peak during startup of 30M; to boot process, along with a large number of temporary objects created, they Chaosheng Xi die, soon to be recovered out:

As shown above, this is a memory usage App certain times during startup; we have seen a lot of short lines, jargon is called jitter memory; reason, we are also very clear - there are plenty of temporary object is created. How to deal with it? Some people say, do not create a large number of temporary objects. I know all the truth, but can not. For many large App, the process started is quite complex, and many operations can not simply drop removed. So the question is, 30M is not a very large number, why the system is so panic, but also need to keep dropping recovered memory?

There is a cold called your mother think you're cold. Garbage collection is not to say there is garbage before going to recover, but as long as you feel that the system will need to be garbage.

Well, it can not be allowed during the boot process heap GC to maintain sustained growth without it? After all, 30M and will not cause any OOM. What causes the system does not do that? The answer is that free memory. For example, there is a beginning heap 8M, with the progress of the boot process heap to grow to 24M; this time performed a GC, recover lost 8M memory, also returned to the heap 16M; we have 8M of free memory. The system will say, young man, you are taking so much free memory is doing it? Mom to help you keep, so you have left is the memory of 2M free. But clearly the use of heap memory App will soon be more than 18M, so he initiated a series of GC and heap size adjustment, again and again until smooth start to complete the memory. So far, we have been very clear conclusion:

If we can adjust heap_min as Free and heap_max as Free , will be able to greatly influence the process of the GC

How to adjust the size of these two parameters it? Heap pointer to get the object, find the offset of these two parameters, you can directly modify the memory here need a little bit of knowledge of C ++ memory layout; As for how to get Heap pointer to an object, only to find the answer inside the source code. Here I give the final implementation code:

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;
}

After modifying the startup process memory usage below, we can see that our objective has been achieved:

Incidentally, the above code does not consider any of portability and compatibility, only play the role of presentation. Really put into use is a physical work: First, we rely on the memory layout of a particular version of a class of Android, which offset member variable may be different in different versions; Second, the min as Free and max as Free specific adjustments to how closely related to the initial heap size, among other factors configured with the phone's physical memory, App use of memory, the phone; a proper adjustment of parameters takes some time, Android models so much here need some tips.

不知道上面这个例子有木有让你感受到深入系统底层,那种呼风唤雨无所不能的快感?可能很多人觉得我们都是写写if else而已,调节面改动画写业务已经够了;但我想说明的是,深入学习系统原理是非常有好处的,它可以赋予你在应用层永远无法拥有的能力。

自己是从事了七年开发的Android工程师,不少人私下问我,2019年Android进阶该怎么学,方法有没有?

没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助那些想进阶提升Android开发,却又不知道怎么进阶学习的朋友。【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

资料获取方式:加入Android架构交流QQ群聊:513088520 ,进群即领取资料!!!

点击链接加入群聊【Android移动架构总群】:加入群聊

资料大全

Guess you like

Origin blog.csdn.net/weixin_43351655/article/details/91491457