Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the code performance optimization tips of Android Training

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article is about Android Training code performance optimization tips to share with you, the editor feels very practical, so share with you to learn, I hope you can learn something after reading this article, say no more, follow the editor to have a look.

This paper mainly introduces some small details of optimization techniques, although these tips can not greatly improve the application performance, but the proper use of these tips and cumulative effect will play an important role in improving the performance of the whole App.

In general, efficient code needs to meet the following two principles:

Don't do redundant work.

Try to avoid performing too many memory allocation operations

One of the difficulties in optimizing App is to get App to run on all types of devices. Different versions of virtual machines will run at different speeds on different processors. You can't even simply assume that "the speed of device X is F times that of device Y" and then use this multiple relationship to speculate about other devices. In addition, the running speed on the simulator has nothing to do with the speed on the actual equipment. Similarly, whether the device has JIT or not also has a significant impact on the running speed: the * * code in the case of JIT is not necessarily * without JIT.

To ensure that App works well on all devices, make sure that your code is optimized as much as possible on different levels of devices.

Avoid creating unnecessary objects

Creating objects is never free. Generational GC can make the allocation of temporary objects cheaper, but it is always more expensive to allocate memory than not to do so.

As you allocate more objects in App, you may need to force gc, and gc will bring a little stutter to the user experience. Although concurrent gc has been introduced since Android 2.3, which can help you significantly improve the efficiency of gc and reduce stutters, unnecessary memory allocation operations should be avoided.

So try to avoid creating unnecessary objects, and here are some examples to illustrate this:

If you need to return a String object, and you know it will eventually need to connect to a StringBuffer, please modify your function implementation to avoid direct concatenation operations, you should create a temporary object to do string concatenation this operation.

When pulling String from an existing dataset, try to return the substring object of the original data instead of creating a duplicate object. Using substring, you will get a new String object, but this string object shares the internal char [] space with the original string.

A slightly more radical approach is to decompose all multidimensional data into one-dimensional arrays:

A set of int data is much better than a set of Integer objects. As you can see, two sets of one-dimensional arrays are more efficient than one two-dimensional array. Similarly, this principle can be extended to other raw data types.

If you need to implement an array of objects to Foo,Bar, remember that using Foo [] and Bar [] is much better than (Foo,Bar). (as an exception, some compromises can be made for the sake of some good API design. But within your own code, you should use the decomposed easy more.

In general, you need to avoid creating more temporary objects. Fewer objects mean fewer gc actions, and gc will have a more direct impact on the user experience.

Choose Static over Virtual

If you do not need to access the value of an object, make sure that the method is of type static, so that the method call will be 15% faster. This is a good habit because you can tell from the method declaration that the call cannot change the state of the object.

The constant is declared as Static Final

Consider the following way of declaring

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

The compiler uses a function that initializes the class and then executes it when the class is used * times. This function stores 42 in intVal and also extracts a reference to strVal from the constant table in the class file. When you use 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 needed because the constant declared by final enters the domain initialization section of the static dex file. The code that calls intVal uses 42 directly, and the code that calls strVal uses a relatively cheap "string constant" instruction instead of looking up the table.

Notes: this optimization method works only for primitive types and String types, not for any reference type. However, it is a good habit to use static final when necessary.

Avoid internal Getters/Setters

Native language, such as C++, usually uses getters (I = getCount ()) instead of directly accessing the variable (I = mCount). This is an excellent habit for writing C++, and it is usually used by other object-oriented languages, such as C # and Java, because the compiler usually does 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 way to write. Calling a virtual function is more expensive than accessing a variable directly. In object-oriented programming, it makes sense to expose getter and setting to public interfaces, but only domain direct access should be used within the class.

Without JIT (Just In Time Compiler), accessing variables directly is three times faster than calling getter. With JIT, accessing variables directly is seven times faster than accessing variables through getter.

Please note that if you use ProGuard, you can get the same effect because ProGuard can inline accessors for you.

Use enhanced For loops

Enhanced For loops (also known as for-each loops) can be used on collections and arrays that implement the Iterable interface. When using collection, Iterator is assigned for for-each to call the hasNext () and next () methods. With ArrayList, handwritten counting for loops are three times faster (with or without JIT), but for other collection, enhanced for-each loop writing is as efficient as iterator writing.

Compare the following three methods of looping:

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 JIT has no way to optimize it.

One () is slightly faster.

Two () is the fastest when not doing JIT, but after JIT, it is almost as fast as the method one (). It uses the enhanced loop method for-each.

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

Tips: you can also refer to article 46 of Josh Bloch's Effective Java.

Use package-level access instead of private access to inner classes

Refer to the following 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 is important here is that we define a private inner class (Foo$Inner) that directly accesses private methods and private member objects in the external class. This is legal, and this code will print out "Value is 27" as expected.

The problem is that VM considers it illegal to directly access private members of the Foo class in Foo$Inner because Foo and Foo$Inner are different classes. Even though the Java language allows inner classes to access private members of external classes. To eliminate this difference, the compiler produces some copycat 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 the inner class needs to access a mValue member in the external class or needs to call the doStuff () function. This means that the above code boils down to accessing member variables through the accessor function. As we said earlier, it is slower to access the domain through accessor than directly. So, this is an example of performance degradation caused by specific language usage.

If you are using code like this in a performance hotspot (hotspot: high-frequency, repeatedly executed code snippets), you can declare the fields and methods that the inner class needs to access as package-level access instead of private access. Unfortunately, this means that other classes in the same package can also access these fields directly, so you can't do this in the exposed API.

Avoid using float types

The data access speed of float type in Android system is half of that of int type, and int type is preferred as far as possible.

In terms of speed, in modern hardware, the speed of float and double is the same. Spatially, double is twice the size of float. You should use double when space is not a problem.

Similarly, for integers, some processors implement multiplication of several times the hardware, but there is no division. At this point, the division and remainder of integers are implemented internally in the software, which should be taken into account when you use a hash table or a large number of computations.

Use library functions

In addition to the common reasons for using your own library functions, remember that system functions can sometimes replace third-party libraries, and there are assembly-level optimizations that are usually more efficient than code compiled by Java with JIT. A typical example is String.indexOf () in Android API, which Dalvik replaces for inline performance. The System.arraycopy () function is also replaced, and the performance tested by Nexus One is 9 times faster than a handwritten for loop and using JIT.

Tips: see article 47 of Josh Bloch's "Effective Java"

Use the native function with caution

Using native code development in conjunction with Android NDK is not always more efficient than direct Java development. The conversion of Java to native code comes at a cost, and JIT cannot be optimized in this case. If you allocate resources in native code (such as memory on the native heap, file descriptors, etc.), this can make it extremely difficult to collect these resources. You also need to recompile the code for various architectures (rather than relying on JIT). You even need to compile multiple versions for devices that already have the same architecture: the version compiled for the ARM architecture of G1 does not fully take advantage of the ARM architecture on Nexus One, and vice versa.

Native code is an advantage when you already have native code and want to port it to the Android platform, not to optimize the use of existing Android Java code.

Misunderstandings about performance

On devices without JIT, using an exact data type is indeed more efficient than an abstract data type (for example, calling HashMap map is more efficient than calling Map map). The efficiency of mistransmission is twice as high, but in fact it is only about 6%. And, after JIT, there is not much difference between them directly.

On devices without JIT, reading the cache domain is about 20% faster than reading the actual data directly. With JIT, there is basically no difference between domain reads and local reads. So optimization is not worth it unless you think it makes your code easier to read (the same applies to final, static, and static final domains).

About measurement

Before optimizing, you should make sure that you have a performance problem. You should make sure that you can accurately measure the performance that appears, otherwise you won't know if the optimization is really effective.

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

Benchmark is based on the Java version of the Caliper microbenchmarking framework. Microbenchmarking is hard to be accurate, so Caliper helps you with this part of the work, and even tests the parts you didn't expect to measure (because VM helps you manage code optimization, it's hard to know how effective this part of optimization is). We highly recommend using Caliper to do your benchmark microtesting.

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

These are the tips for Android Training's code performance optimization, and the editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report