In the previous article, there are many performance and memory tips that need to be noted in the development of Android apps. This article is an analysis of performance optimization and memory optimization issues from the Smali instruction level.
How to solve the problem of high interface start time overhead
When we write Android applications, there are many situations where the interface is too long to start and the user experience is very bad. So when we write code, we must pay more attention to how to improve the start time of the interface. Here are a few tips on how to optimize the interface startup overhead.
1. Load overhead for classes
When a static method or static property of a class is called or the class is instantiated, the first thing the virtual machine does is dexclassloader the class file to the virtual machine, and the process of loading into the virtual machine triggers the execution of the Clinit function in the class file. Let's look at the following section of code
[CPP]View Plaincopy
- Package Com.example.smalidemo.foreach;
- Import java.util.ArrayList;
- Import java.util.List;
- Public class Oninittest {
- public static final String init_string = "Initstring_fantasy";
- public static String init2_string = "for Initstring_fantasy 2";
- private String init3_string = "Initstring_fantasyh 3";
- public static final int int_1 = 100;
- public static int init_int = 10000;
- public static List List = new ArrayList ();
- public static final arraylist<appbean> mapplistoninit = new arraylist<appbean> ();
- public static ArrayList mapplist = null;
- private static String string_array[] = { "jpg", "MP5", "mp4"};
- private static final String final_string_array[] = { "pdf", "txt",
- "EXE"};
[CPP]View Plaincopy
- }
Post-compilation Smali files
[HTML]View Plaincopy
- . class public lcom/example/smalidemo/foreach/oninittest;
- . Super Ljava/lang/object;
- . Source "Oninittest.java"
- # static fields
- . field private static final final_string_array:[ljava/lang/string; = null
- . field public static init2_string:ljava/lang/string; = NULL
- . field public static init_int:i = 0x0
- . field public static final init_string:ljava/lang/string; = "Initstring_fantasy"
- . field public static final int_1:i = 0x64
- . field private static string_array:[ljava/lang/string;
- . field public static list:ljava/util/list;
- . field public static mapplist:ljava/util/arraylist;
- . field public static final mapplistoninit:ljava/util/arraylist;
- . annotation system ldalvik/annotation/signature;
- value = {
- "Ljava/util/arraylist",
- "<",
- "Lcom/example/smalidemo/foreach/appbean;",
- ">;"
- }
- . End annotation
- . End Field
- # instance Fields
- . field private init3_string:ljava/lang/string;
- # Direct methods
- . method Static constructor <clinit> () V
- . Locals 10
- . Prologue
- CONST/16 V9, 0x2710
- CONST/4 V8, 0x3
- CONST/4 V7, 0x2
- CONST/4 V6, 0x1
- CONST/4 V5, 0x0
- . Line 8
- Const-string v3, "for Initstring_fantasy 2"
- Sput-object v3, lcom/example/smalidemo/foreach/oninittest;->INIT2_STRING:Ljava/lang/String;
- . Line 11
- Sput v9, lcom/example/smalidemo/foreach/oninittest;->init_int:i
- . Line 12
- New-instance v3, ljava/util/arraylist;
- Invoke-direct {v3}, ljava/util/arraylist;-><init> () V
- Sput-object v3, lcom/example/smalidemo/foreach/oninittest;->list:Ljava/util/List;
- . Line 13
- New-instance v3, ljava/util/arraylist;
- Invoke-direct {v3}, ljava/util/arraylist;-><init> () V
- Sput-object v3, lcom/example/smalidemo/foreach/oninittest;->mAppListOnInit:Ljava/util/ArrayList;
- . Line 14
- CONST/4 v3, 0x0
- Sput-object v3, lcom/example/smalidemo/foreach/oninittest;->mAppList:Ljava/util/ArrayList;
- . Line 15
- New-array v3, V8, [ljava/lang/string;
- Const-string v4, "JPG"
- Aput-object v4, v3, v5
- Const-string v4, "MP5"
- Aput-object v4, V3, V6
- Const-string v4, "MP4"
- Aput-object v4, v3, V7
- Sput-object v3, lcom/example/smalidemo/foreach/oninittest;->STRING_ARRAY:[Ljava/lang/String;
- . line 16
- New-array v3, V8, [ljava/lang/string;
- Const-string v4, "PDF"
- Aput-object v4, v3, v5
- Const-string v4, "TXT"
- Aput-object v4, V3, V6
- . Line 17
- Const-string v4, "EXE"
- Aput-object v4, v3, V7
- . line 16
- Sput-object v3, lcom/example/smalidemo/foreach/oninittest;->FINAL_STRING_ARRAY:[Ljava/lang/String;
- . Line 20
- CONST/4 v1, 0x0
- . Local V1, i:i
- Move v2, V1
- . Line 21
- . End Local V1 #i: I
- . Local v2, I:i
- : goto_0
- ADD-INT/LIT8 v1, v2, 0x1
- . End Local V2 #i: I
- . Restart Local V1 #i: I
- IF-LT v2, V9,: cond_0
- . Line 25
- Return-void
- . Line 22
- : Cond_0
- New-instance V0, Lcom/example/smalidemo/foreach/appbean;
- Invoke-direct {v0}, lcom/example/smalidemo/foreach/appbean;-><init> () V
- . line 23
- . local V0, Bean:lcom/example/smalidemo/foreach/appbean;
- Sget-object v3, lcom/example/smalidemo/foreach/oninittest;->mAppListOnInit:Ljava/util/ArrayList;
- invoke-virtual {v3, v0}, ljava/util/arraylist;->add (ljava/lang/object;) Z
- Move v2, V1
- . End Local V1 #i: I
- . Restart Local v2 #i: I
- Goto:goto_0
- . End method
In the Java file above, we declare a number of variables, including strings, integers, arrays of strings, some of which declare final, and some do not declare final. We can see that the final string and integer are declared, the compiled file has become a constant, and no final variable is declared, and we can see that the default value of string, which is still the type default value, is null at the point where it is declared, and the default value of int is 0. So when Dexclassloader loads the class file, it will initialize the values for the above static variables in the <clinit> function. We can see that a number of static variables are declared, in the compiled Smali file, become more Smali instructions.
Increasing the speed of the Dexclassloader loading class is to improve the execution speed of the <clinit> function in class.
Through the above analysis we can summarize the following rules:
Declare a static variable, be sure to add a final declaration (the compiler variable is replaced by the constant, it will not load the CPU time when the class loaded)
2. Creating instance overhead for classes
In addition to static variables in a class file, there are many global non-static variables. When we declare global variables, we assign values to global variables.
[CPP]View Plaincopy
- Private String init3_string = "Initstring_fantasyh 3";
This Java statement above will become a few instructions in the Smali file. Let's take a look at:
[HTML]View Plaincopy
- # instance Fields
- . field private init3_string:ljava/lang/string;
[HTML]View Plaincopy
- . method Public constructor <init> () V
- . Locals 1
- . Prologue
- . Line 6
- Invoke-direct {p0}, ljava/lang/object;-><init> () V
- . Line 9
- Const-string V0, "INITSTRING_FANTASYH 3"
- Iput-object V0, P0, lcom/example/smalidemo/foreach/oninittest;->INIT3_STRING:Ljava/lang/String;
- . Line 6
- Return-void
- . End method
As you can see, in the <init> function, the global non-static variables are initialized. Class file is the process of executing the <init> function when creating instances of classes.
The process of improving the class creation instance is the process of optimizing <init> function execution speed. Our best practice is to assign a default value where the global variable is declared, and then initialize it when it is actually used in the function.
Whether we are static global variables or non-static global variables, these variables are assigned during class loading and instantiation. If we assign a value at the time of the declaration, we assign a value to the INIT function, or else an assignment of NULL or 0 is executed. Therefore, it is a great rule to declare global variables as few as possible. (because whenever a global variable is declared, an instruction is executed when the class is loaded or initialized.) )
The above two points are optimized, I believe that the display speed of the interface to improve a lot.
But when we need to define a set or array of constants in our code, how can we avoid the overhead of these two processes? For example, in development, we need to define a static global array. If defined in a class that is instantiated in the activity's oncreate, it will certainly consume a lot of activity startup time. How do you optimize for this problem? We can refactor this static array into another class, and we can call the static array in this class directly when we use the array. This avoids the problem of initializing the majority of groups in the activity initialization process.
Lazy initialization is a powerful technique for optimizing activity startup time. On the basis of not modifying the algorithm and the logical structure, the delay initialization can also achieve a certain degree of optimization.
Through the above analysis can summarize the following several rules:
1. Declare global variables as few as possible
2. Declaring a static variable must be a final statement
3. For large overhead static modules or global non-static modules, can be refactored into another class, to achieve the role of lazy initialization.
Excerpt from: http://blog.csdn.net/litton_van/article/details/21872677
Go Android High Performance Programming (2)--deferred initialization