Android Performance Optimization Performance Tips

Source: Internet
Author: User
Tags benchmark

If you really want to work hard, the worst outcome of your life is just bloomer.

Original link: http://developer.android.com/training/articles/perf-tips.html#UseFinal

Overview

This document contains some small optimization optimizations that, when combined, can improve the overall performance of the app, but it is unlikely to have a dramatic impact on performance. Choosing the right algorithm and data structure should be your priority, but beyond the scope of this article. This document is better suited as a generic coding technique that makes our code more efficient.

There are two basic rules for writing efficient code:

    • Do not perform unnecessary operations

    • Do not allocate unnecessary memory

One of the toughest problems we face is that our Android apps will definitely run on multiple types of hardware. The speed at which different versions of VM VMs run on different processors is obviously different. You can't even simply say "device x is faster/slower than device y is about f times", and then take it for granted that this multiple on his device is also true. However, we can only get very little information about the performance of the device from the simulator, which is very different from the real machine. Also, there is a huge difference between devices with or without JIT (Instant compilation): Code that runs flawlessly on a JIT-capable device does not necessarily run smoothly on devices that have no JIT.

We try to optimize performance to ensure that our applications perform well on a wide variety of devices, ensuring that the code is valid on the different versions supported.

Avoid creating unnecessary objects

Object creation is never free. Although a garbage collector with a thread pool (garbage collector) can reduce the memory footprint of allocating temporary objects, allocating memory is always more expensive than allocating memory.

When we allocate more objects in our application, we will force a recurring garbage collection to create a "hiccup" user experience, which is the stutter. The Concurrent garbage collector (GC) introduced in Android 2.3 can help us, but unnecessary work can be avoided to avoid as much as possible.

So we should avoid creating objects that we don't need, and here are some examples:

    • If you have a method that returns a string, you know that its result needs to be appended to the stringbuffer, changing your implementation so that it can be added directly instead of creating a temporary object.
    • When you want to extract a string from a set of input data, try to return a substring of the original data (substring) instead of creating a duplicate object. Using substring, you will create a new string object, but it will share the internal char[] space with the original data. (If you only use a small fraction of the original input, you'll keep it in memory, regardless of how it's done, it's a tradeoff)

A more radical idea is to split a multidimensional array into a parallel one-dimensional array:

    • An array of type int is better than an array of integer objects, thus knowing that two parallel int arrays are more efficient than (int,int) two-dimensional arrays. The same applies to all raw data types.
    • If you need to implement a container storage (Foo,bar) object, try to remember that two parallel foo[] and bar[] arrays are usually better than custom (Foo,bar) objects for a single array. (There are exceptions, such as when you design an API to access other code.) In these cases, it is often possible to sacrifice a small fraction of performance to achieve a good API design. But in our own internal code, we should try to improve efficiency as much as possible. )

In general, avoid creating temporary objects. Fewer object creation means less garbage collection, which has a direct impact on the user experience.

Choose static instead of virtual

If you don't need to access the fields of an object, you can use static to decorate your method. The call will be fast 15%~20%. This is a good practice because by using static you can also know that the method being called does not change the state of the object.

Using the static final modifier constants

Declare constants at the top of a class like this:

static int intVal = 42;static String strVal = "Hello, world!";

The compiler generates a class initialization method called < Clinit, which executes when the class is used for the first time. This function stores 42 in Intval and extracts the Strval reference from the constant table of the class file. When using Intval or Strval later, they will be queried directly.

We can use the final keyword to optimize:

static final int intVal = 42;static final String strVal = "Hello, world!";

The above method is no longer required because the constants of the final declaration enter the domain initialization part of the static Dex file. The code that calls Intval uses 42 directly, and the code that calls Strval uses a relatively inexpensive "string constant" instruction instead of a table.

Notes: This optimization method is valid only for the original type and string type, not for any reference type. However, it is a good practice to use static final when necessary.

Avoid internal getters/setters.

Native language, such as C + +, typically use getters (i = GetCount ()) instead of directly accessing the variable (i = mCount). This is a good habit of writing C + + and is often used by other object-oriented languages, such as C # and Java, because compilers usually do inline access, and you need to restrict or debug variables, you can add code to getter/setter at any time.

However, on Android, this is not a good notation. The call to a virtual function consumes more than a direct access variable. In object-oriented programming, it is reasonable to expose getter and setting to the public interface, but within the class you should only use domain direct access.

When there is no JIT (Just in time Compiler), direct access to the variable is 3 times times faster than the call getter. When there is a JIT, direct access to the variable is 7 times times faster than the getter access.

Please note that if you use Proguard, you can get the same effect because Proguard can be accessed for you inline.

Using the For-each loop

The enhanced for loop (also known as the For-each Loop) can be used on collections and arrays that implement the Iterable interface. When using collection, iterator is allocated for For-each calls to the Hasnext () and Next () methods. With ArrayList, the handwritten count for loop will be 3 times times faster (with or without JIT), but for other collection, the enhanced For-each loop will be as efficient as the iterator notation.

Please compare the following three loops:

static class Foo {    int mSplat;}Foo[] mArray = ...public void zero() {    int sum = 0;    for (int i = 0; i < mArray.length; ++i) {        sum += mArray[i].mSplat;    }}public void one() {    int sum = 0;    Foo[] localArray = mArray;    int len = localArray.length;    for (int i = 0; i < len; ++i) {        sum += localArray[i].mSplat;    }}public void two() {    int sum = 0;    for (Foo a : mArray) {        sum += a.mSplat;    }}

-Zero () is the slowest, because the JIT has no way to optimize it.
-One () is a little faster.
-Double () is the quickest when it is not JIT, but it is almost as fast as method one () if it has been JIT. It uses the enhanced loop method For-each.

So try to use the For-each method, but for ArrayList, use method one ().

Tips: You can also refer to the 46th of the book "Effective Java" from Josh Bloch

Use package instead of private for efficient access to external class members by private internal classes

Refer to the following section of code

public class Foo {    private class Inner {        void stuff() {            Foo.this.doStuff(Foo.this.mValue);        }    }    private int mValue;    public void run() {        Inner in = new Inner();        mValue = 27;        in.stuff();    }    private void doStuff(int value) {        System.out.println("Value is " + value);    }}

What's important here is that we define a private inner class (Foo$inner) that accesses private methods and private member objects directly in the outer class. This is legal, and the code prints "Value is 27" as expected.

The problem is that VMS (virtual machines) because Foo and foo I NNeRis aNowithof theclass,will berecognizeto bein theF oo It is not legal to access the private members of the Foo class directly in inner. Even though the Java language allows internal classes to access private members of external classes. To get rid of this discrepancy, the compiler produces some imitation functions:

/*package*/ static int Foo.access$100(Foo foo) {    return foo.mValue;}/*package*/ static void Foo.access$200(Foo foo, int value) {    foo.doStuff(value);}

It calls these static methods whenever an internal class needs to access an Mvalue member in an external class or needs to call the Dostuff () function. This means that the above code can be attributed to the use of the accessor function to access the member variable. As we said earlier, passing accessor would be slower than accessing the domain directly. So, this is an example of a performance degradation caused by a particular language usage.

If you are using code like this in the performance Hot Zone (hotspot: High frequency, repeating code snippet), you can declare the domains and methods that the inner class needs to access as package-level access, rather than private access. Unfortunately, this means that other classes in the same package can also access these domains directly, so you cannot do so in the exposed API.

Avoid using floating-point types

The data access speed for the float type in Android is half the type of int, as much as possible with the int type.

In terms of speed, the speed of float and double is the same on modern hardware. In terms of space, double is twice times the size of float. In situations where space is not an issue, you should use double.

Similarly, for integer types, some processors implement multiplication of hardware several times, but no division. At this point, the division and remainder of the integer is implemented within the software, which you should take into account when you use a hash table or a large number of computation operations.

Understanding and Using Library functions

In addition to the usual reasons for you to use your own library functions, remember that system functions can sometimes replace third-party libraries, and there are assembly-level optimizations that are often more efficient than code with JIT-compiled java. A typical example is the String.IndexOf () in the Android API, which is replaced by Dalvik for inline performance reasons. The same system.arraycopy () function is also replaced, so the performance is 9 times times faster than the handwritten for loop and using the JIT in the Nexus One Test.

Tips: See the 47th article of the book "Effective Java" by Josh Bloch

Be careful with the underlying approach

Combining the Android NDK with native code development is not always more efficient than direct Java development. Java-to-native code is a cost, and JIT cannot be optimized in this case. If you allocate resources in the native code (such as memory on the native heap, file descriptors, and so on), this can cause great difficulty in collecting these resources. You also need to recompile the code for various architectures (rather than relying on JIT). You even need to compile multiple versions of a device that already has the same architecture: the version compiled for the G1 arm architecture does not fully utilize the benefits of the ARM architecture on Nexus One, and vice versa.

The Native code is an advantage when you already have native code that you want to port to the Android platform, rather than to optimize the existing Android Java code usage.

If you want to use JNI, learn JNI Tips

Tips: See the 54th article of the book "Effective Java" by Josh Bloch

See the Performance fallacy

On devices that do not have a JIT, it is really more efficient to use an exact data type than the abstract data type (for example, calling HashMap map is more efficient than calling map map). There is a high rate of misinformation, actually just about 6%. Moreover, after the JIT, they are directly not the most difference.

On devices that do not have a JIT, reading the cache domain is about 20% faster than reading the actual data directly. When there is a JIT, the domain reads and the local reads basically no difference. So optimization is not worth it unless you think it makes your code easier to read (which is also true for final, static, static final fields).

About measurement

Before you optimize, you should make sure that you are experiencing performance problems. You should make sure that you can accurately measure the current performance, otherwise you will not know whether the optimization is really effective.

All the techniques in this section require benchmark (benchmark) support. Benchmark can be found in code.google.com "Dalvik" project.

Benchmark was developed based on the Java version of the Caliper microbenchmarking framework. Microbenchmarking is difficult to do accurately, so caliper help you with this part of the work, and even help you to test the parts you did not expect to measure (because, the VM to help you manage the code optimization, you can hardly know how much of this optimization effect). We highly recommend using caliper to do your benchmark work.

We can also use TraceView to measure, but the measured data is not JIT-optimized, so the actual effect should be slightly better than the measured data.

You can also refer to the following two articles on how to measure and debug:

    • Http://developer.android.com/tools/debugging/debugging-tracing.html
    • Http://developer.android.com/tools/debugging/systrace.html

Android Performance Optimization Performance Tips

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.