Original address: http://android.xsoftlab.net/training/articles/perf-tips.html
This article focuses on the small optimization points that can improve overall performance. It does not belong to the same class as those that can suddenly change the performance effect. Choosing the right algorithm and data structure is necessarily our first general principle, but this is not what we want to introduce in this article. You should use the knowledge points mentioned in this article as the daily habit of coding, which can improve the efficiency of regular code execution.
Here are the basic guidelines for writing code:
- Never do a job you don't need.
- If you can not apply for memory, do not apply, it is reasonable to reuse the existing objects.
Another more complex problem is that the optimized app must be running on various types of hardware platforms. Different versions of a virtual machine running on different processors will certainly run at different speeds. Specifically, testing on the simulator will rarely tell you about the performance of other devices. There is a big difference between devices that there is no JIT (JIT means an instant compiler): the best code to run on a JIT device is not always valid on a JIT device.
To ensure that the app works well on a variety of devices, make sure that the code is efficient on every version of the platform.
Avoid creating unnecessary objects
Creating objects is never cost-free. Although the generational garbage collector can make the allocation cost of temporary objects very low, the cost of allocating memory is always much higher than the cost of non-memory allocations.
As more objects are generated, you may start to focus on the garbage collector. While the concurrent collectors that appear in Android 2.3 may help you, unnecessary work should always be avoided.
Therefore, avoid creating objects that you do not need. The following example may help you:
- If you have a method that returns a string, the string returned by the method is always followed by a StringBuffer object. Then you can change the way this method is implemented: Let the string be returned directly after the StringBuffer. This prevents the creation of temporary variables.
- When you extract a substring from a string, you should try to return the substring of the original data instead of creating a copy. The substring will create a new string object, but it is the same data that is shared with char[]. The only disadvantage in this way is that although some of the data is used, the remaining data remains in memory.
A more advanced rule is to convert a multidimensional array to a parallel array using:
- The efficiency of an int array is much more efficient than an integer array.
- If you need to implement an array for storing (Foo,bar) objects, remember to use two parallel foo[],bar[] arrays, which is much more efficient than a single (Foo,bar) array.
In general, try to avoid creating temporary variables that have a short life cycle. Fewer object creation means lower-frequency garbage collection, which directly responds to the user experience.
Preferred static
If you do not need to access the properties of an object, you can set the method to a static method. This will increase the speed of 15%-20%. This is a good habit, because it can tell other methods a signal that they cannot change the state of the object.
Using constants
Please consider the following statement first:
staticint42;static"Hello, world!";
The compiler generates an instantiation method for a class called < Clinit>, which executes when the class is first used. This method saves the value 42 to intval and assigns the reference in the string constant table to Strval. When these values are referenced, other properties can access them.
We can use the "final" keyword to improve:
staticfinalint42;staticfinal"Hello, world!";
In this case, the class does not need to call the < Clinit> method again, because the initialization of the constant is moved into the Dex file. The code can refer directly to a value of Intval 42, and access to Strval will also directly get the string "string constant", which eliminates the process of finding a string.
Note: This optimization method only applies to basic data types and string constants, and does not work with other types.
Avoid the internal Get\set method
Native languages like C + + typically use the Get method to access properties. This is a good habit for C + + and is widely used in object-oriented languages such as C # and Java, because compilers typically do inline access, and if you need to restrict access or debug properties, you just need to add code.
However, this is not a good habit on Android. The cost of a method call is very large. Although it is reasonable to provide get and set methods in order to follow the object-oriented language, it is best to have direct access to the fields of the object in Android.
In devices that do not have a JIT, direct access to object fields is 3 times times faster than accessed by the Get method. This is 7 times times more efficient in devices that contain JIT.
Note: If you use Proguard, then you have a result of both worlds, because Proguard will directly provide you with inline access.
Using the enhanced for loop
The enhanced for loop can be used to implement a collection or an array of iterable interfaces. Inside the collection, the iterator needs to implement the interface method: Hasnext () and Next ().
There are several ways to access an array:
StaticClass Foo {intMsplat;} foo[] Marray = ... Public void Zero() {intsum =0; for(inti =0; i < marray.length; ++i) {sum + = Marray[i].msplat; }} Public void One() {intsum =0; foo[] LocalArray = Marray;intlen = localarray.length; for(inti =0; i < Len; ++i) {sum + = Localarray[i].msplat; }} Public void Both() {intsum =0; for(Foo A:marray) {sum + = A.msplat; }}
The zero () method is the slowest because the JIT is not able to optimize the cost of each access to the array length.
The one () method is a little faster. It puts all the elements into local variables, which avoids every query. Only the length of the array provides a noticeable performance boost.
The () method is the fastest. It uses the enhanced for loop.
Therefore, the enhanced for loop should be used by default.
Tip: You can also view Josh Bloch's effective Java, 46th.
Consider using in-package access
Consider the following class definitions first:
Public class Foo { Private class Inner { voidStuff () {Foo. This. Dostuff (Foo. This. Mvalue); } }Private intMvalue; Public void Run() {Inner in =NewInner (); Mvalue = -; In.stuff (); }Private void Dostuff(intValue) {System.out.println ("Value is"+ value); }}
The code above defines an inner class that can directly access private members of external classes and private methods. This is correct, and this code will print out what we expect "Value is 27".
The problem here is that theVM will think that foo$Inner directly access the private members of the Foo object is illegal because Foo and foo$inner are two different classes, Although the Java language allows internal classes to directly access private members of external classes (PS: virtual machines and languages are two non-interfering existence ). To compensate for this discrepancy, the compiler generates a set of methods specifically for this purpose:
/*package*/staticint Foo.access$100(Foo foo) { return foo.mValue;}/*package*/staticvoid Foo.access$200int value) { foo.doStuff(value);}
These static methods are called when the internal class code needs to access the property mvalue or call the Dostuff () method. The above code boils down to that the member properties you access are accessed through accessor methods. Earlier we said that access through accessors is much slower than direct access, so this is an example of the implicit performance overhead of a particular language.
Avoid using floating-point types
Generally speaking, the floating point of the Android device is about twice times slower than the integer type.
In terms of speed, there is no difference between a float and a double. In terms of space, double is twice times the size of float. So on desktop-level devices, assuming that space is not a problem, then we should prefer double, not float.
Also, some processors are adept at multiplication and are not good at division in the treatment of integral types. In this case, the integer division and modulo operations are done in software, and if you are designing a hash table or doing a lot of other math, these things should be considered.
Use local methods Be careful
Apps developed using native code are not necessarily much more efficient than those written in the Java language. First, it is spent in the conversion process of java-native code, and the JIT is not optimized to these boundaries. If you are applying for local resources, you can obviously feel the difficulty of collecting these resources. In addition, you need to compile each CPU architecture separately. You may even need to compile several different versions for the same CPU architecture: code compiled for G1 ARM processors cannot run on Nexus One arm processing, and the code compiled for Nexus One's arm processor will also not run on G1 's arm processor.
Local code is appropriate in this case: when you have an existing local code base and you want to port it to Android, do not use native code to improve the speed of code written by the Java language.
If you need to use local code, you should read the JNI Tips.
TIP: information can also be viewed in effective Java, 54th of Josh Bloch.
Performance Myths
In a device that does not have a JIT, it is true that calling a method through a specific type of variable is more efficient than an abstract interface invocation. For example, the HashMap map call method is more efficient and less expensive than the map map call method, although both implementations are hashmap. In fact, the speed is not twice times slower so much; the real difference is about a 6% slowdown. Further, the JIT will make the difference between the two further narrow.
On devices that do not have a JIT, accessing the property through the cache is nearly 20% faster than repeatedly accessing the property. In a JIT device, the cost of property access is basically the same as the expense of local access, so this is not a much-valued optimization, unless you think the code is easier to read (which is also true for static,final, constants).
Often estimated
Before you start optimization, make sure you have a problem to solve: Make sure you can measure your existing performance accurately, or you will not be able to observe the improvements brought about by optimization.
The datum point is created by the caliper's Micro datum frame. The datum points are hard to get right, so caliper does the hard work, even when you're not measuring where you want to measure it. We strongly recommend that you use Caliper to create your own miniature datum points.
You may also find that TraceView is very helpful in improving performance, but you should be aware that the JIT does not turn on when TraceView is working. It would be wrong to assume that the JIT will compensate for the lost time. This is especially important: depending on the results of the TraceView, the actual code will run faster.
For more tools and methods to enhance your app's performance, see the following documentation:
- Profiling with Traceview and Dmtracedump
- Analyzing UI performance with Systrace
Android Official Development Document Training Series Course Chinese version: Performance Tuning recommendations