background
As mobile application development becomes more and more streamlined, more and more applications appear on the market. However, developing a mobile application is not a simple process and takes a lot of time, especially if you want a scalable mobile application that can run across Apple, Android, and Windows.
However, poor performance may greatly harm the user experience. The user does not want to see the startup screen longer than 10 seconds at any time. If the waiting time is too long, they may feel overwhelmed, give up shopping, reduce their stay time, or completely uninstall the application.
With the popularity of development platforms, we need the right tools and methods to meet the ever-increasing demand.
Xamarin is such a framework, which supports the sharing of a single code base on Android, iOS and Windows platforms.
Therefore, we will test the performance in the Xamarin.Android application, just like using Java development in Android Studio, we can use c# to test the performance to optimize the startup time.
Total test start time
First, test the startup time of the program on different devices. The tool used here is U-APM launched by Youmeng+. It can be seen from the figure that there is still room for optimization in the startup time of the application.
On Android, the ActivityManager system process will display an "initial display time" log message to better understand the overall startup time. Use adb logcat in the command line to quickly view the Android device log. Or use the Android debug log in Visual Studio.
On Windows, run the following powershell:
Output:
The above log messages were captured when debugging the application from Visual Studio on the x86 Android emulator. Starting/connecting the debugger will incur some additional overhead and lack of optimization during Debug compilation.
If we simply switch to the Release configuration and deploy and run the application again:
If we test the application on a Pixel 3 XL device:
Because our ultimate goal is to improve the performance of mobile applications, the first step should be to actually test the specific location of the stuttering function. If you make changes to the code blindly, you may end up with a very big difference from our speculated results. If some complex performance improvements are made, the maintainability of the code base will even be damaged. This process should be: test, make changes, test again, and repeat the above steps.
The stuck position measured by U-APM mainly appears in:
Diagnose the problem
Well, the previous application is slow due to readRawTextFile. what should I do now?
First, we need to have a systematic understanding of the following components
Android ART
Android runtime (ART) is a managed runtime used by apps and system services on Android. ART is a Dalvik executable file that is executed during operation (.dex file-Dalvik EX executable file), which is a compact format for storing Dalvik bytecode.
ART introduces ahead of time (AOT) compilation by compiling the entire application into native code when installing the application. This leads to faster application execution and improved memory allocation. And garbage collection mechanism, more accurate analysis, etc.
To achieve this, ART uses dex2oat to create an executable file in ELF (executable and link format). The disadvantage is that it takes extra time to compile. In addition, the application uses a large amount of disk memory to store the compiled code.
Mono provides AOT function during operation. Mono will pre-compiled assemblies to minimize JIT time and reduce memory usage. Mono can generate ELF .so files on platforms that support it (such as Android). Then it stores a pre-compiled image next to the original assembly.
which is
Then, these files can be used by Mono during runtime, and JIT overhead is omitted
Start tracking
Mono introduces a feature that allows the built-in AOT analyzer to be used in the application to generate AOT configuration files. The analyzer performs memory analysis, execution time analysis, and even sampling analysis based on statistics. This will generate an AOT configuration file, which can be used to optimize the application when using the AOT function of Mono with the configuration file.
Start tracking can be used in Visual Studio 2019 version 16.2 or Visual Studio for Mac 2019 version 8.2.
You can start using startup tracking by editing the .csproj file of the Android project and adding the following properties in Release <PropertyGroup>:
You can also set it in the Android options of the item settings. Mono's AOT compiler activation will configure the startup tracking of the file by default, and speed up the startup time of the Android application during deployment.
Actual analysis
We need to actually analyze our code and need to improve. Switch back to the Debug configuration and enable the Mono analyzer by running the following command:
adb shell runs a single shell command on an Android device or emulator. setprop sets Android system properties, similar to environment variables on other platforms.
Then just force quit and restart the application. The next time it starts, Mono will save a file in the local directory of the Android application. profile.mlpd
Note that there is a problem with this. The file can only be accessed by the application itself, so we must use the command to locate the file: run-as
In order to get the files from the device, I used a known writable directory, for example: /sdcard/Download/
After copying the file, you can use adb pull to get the file to your desktop computer: profile.mlpd
profile.mlpd is a binary file,
Windows users need to install Mono on the Windows sub-system for Linux to run.
With the series of codes above, some interesting numbers will appear.
solution
Through the previous call, we can find that the following functions may take a considerable amount of time:
You can also see the memory allocation, for example:
Please note that if you need to see which method these assignments came from, you can pass it to. --tracesmprof-report
We have made various attempts and have all received certain results. But what we most unexpectedly did was the following simple change. We try to read the string directly from the stream, instead of creating it with the content of the response, and then use the new
System.Text.Json library for more efficient JSON parsing:
Looking at the difference in method call, we can see an obvious time optimization:
We can also see the following differences in memory allocation:
This is consistent with the bottleneck function we tested in U-APM. The bottleneck is indeed in the readRawTextFile function. We tried the following methods, which alleviated the startup problem to some extent, but the benefits were not Not as large as readRawTextFile in U-APM. Listed here for reference only:
- We can cache the results of web requests
- We can load the previous call result from the file on the disk, which is valid for 24 hours.
- Since the calls are not dependent on each other, we can make asynchronous calls at the same time
- On the server side, we can make a new API call and return all the called data in one request
Conclusion
Optimizing performance is difficult, and there are many directions. Regarding the slow positioning part of the code, after the change, you may find that this part has no effect at all. The best way to affect the code is to test, test, and then test again. Test again after changing. To improve performance through testing, it is often possible to prepare for problems in advance. It also tends to improve the core performance bottleneck more intensively, which brings about an overall improvement of the surface.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。