Android performance optimization is a non-trivial problem for developers. If the performance of the software is very poor, resulting in interface lag, or even directly down, it is extremely fatal for users, and may lead to users directly uninstall the application. On the contrary, if the performance is optimized to the extreme, running smoothly, so as to increase user goodwill, praise, so performance optimization is very important for developers.
Performance optimization for Android usually involves memory leak detection, rendering performance optimization, power optimization, network optimization, Bitmap memory management optimization, multithreading optimization, etc. Of course, performance optimization is not only these, but also installation package optimization and data transfer efficiency, etc. So the performance optimization of Android involves a wide range. A watched pot never boils, so we need to learn little by little and study slowly.
Memory leaks
Memory leakage is related to the developers themselves to write code, so usually developers to write code to have rigor and clear logic, the application of memory, useless, to release. So what is a memory leak?
To understand memory leaks, we first need to understand Java memory allocation, which mainly includes static storage area, stack area, heap area, register, constant pool and so on.
Static storage: The memory is allocated when the program is compiled. This memory persists for the entire runtime and holds static data, global static data, and constants.
Stack area: Holds values of local variables, including values for basic data types, instances of classes (i.e. references (Pointers) to heap objects), and frames for loading methods. This means that some internal variables of a function are stored on the stack, and when the function is finished, these storage units are automatically released. Because the stack memory is built into the processor, so the calculation speed is very fast, but the stack area is limited.
Heap area: Also called dynamic memory allocation, used to store dynamically generated data, such as new objects. Use malloc or new to request a memory allocation. In C/C++ you might be responsible for the release, but in Java you rely directly on GC.
Register: JVM internal virtual register, access speed is very fast, the program can not control.
Constant pool: Stores constants.
For details on memory allocation, please refer to the Java Memory Allocation Overview.
The difference between stack and heap: 1) heap is a discontinuous area of memory, the heap space is relatively flexible and particularly large. 2) Stack type a contiguous memory area, the size is determined by the operating system.
Because the heap is a discontinuous area of memory, it is particularly troublesome to manage. If frequent new and remove, it may cause a large amount of memory fragmentation, resulting in memory leaks, which will lead to low operating efficiency. But for the stack, the characteristics of the stack is advanced after out, in and out will not generate debris, high efficiency and stable operation. So we’re looking at heap memory in terms of memory leaks.
Memory leak: A program that requests memory and then fails to release the requested memory. That is, when an object is no longer in use and should be recycled, it cannot be recycled because another object in use holds a reference to it. This causes objects that should have been collected to remain in heap memory instead of being collected, resulting in a memory leak.
Out of memory
Out of memory: a program is out of memory when it does not have enough memory space to use. On Android, if you run out of memory, which we often see in OOM, the app will flash back. Due to memory leaks, the available memory space becomes less and less, resulting in OOM. So writing code in general requires a major memory leak, because once a memory leak occurs, as more and more memory is leaked, it will cause an overflow of memory.
Since memory leaks cause memory leaks, you need to optimize memory leaks after all. To optimize memory leaks, you need to find the source of the leak before you can optimize it.
Determine memory leaks
1) Memory analysis using Memory Monitors that comes with AndroidStudio.
Through visualization, you can observe the Memery, CPU, NetWork, and GPU changes of the application. Here we will focus on Memery (memory). The picture above shows Memery when I open the app’s home page.
Then click InitiateGC a few times:
This is what happens when you hit GC and it stabilizes, basically a horizontal line.
Free: Indicates the available memory, which is indicated in light gray in the figure. Allocated memory: Allocated memory size, also in blue
When I go to the next page, THE memory change is obvious
When I go back to the previous page, then GC
The figure above is the situation where Free and Allocated tokens are not changed after the return, so there is no memory leak in the newly entered page. If the change is obvious, it can be determined that the newly entered page has memory leak. Memory leaks can also be observed using the Heap Viewer.
Heap Viewer
Heap Viewer: Can look at the size of memory allocated by an App and the size of free memory in real time and detect memory leaks. In addition, the Heap Viewer can also detect memory jitter, because during memory jitter, GC occurs frequently. In this case, we only need to turn on the Heap Viewer and observe the data changes. If memory jitter occurs, the data changes frequently in a short time.
Start Heap Viewer:
Select the corresponding package name under the device, and then update Heap
Select Head, then GC
Click Cause GC to see that all the data is updated, and the updated table shows what data is available on the Heap. Select any of the rows to see the detailed data.
The total size of a Data Object is the total amount of memory used by Java objects in the current process. Note that the Total Size value of the data object is normally stable within a limited range. That is to say, due to the good code in the program, there is no case that the object is not garbage collected. On the contrary, if there is no object reference released in the code, the value of Total Size will increase as the number of operations increases.
Clicking on a Class Object immediately brings up a large amount of updated data on the screen. The rectangle lists the amount of memory allocated for that data, as well as the exact capacity. The Heap Viewer effectively analyzes the types of data allocated by programs in the heap, as well as the amount and size.
Allocation Tracker
In addition to the Head Viewer and Memory Monitor, you can also use an Allocation Tracker.
For more information about Allocation Tracker, see The Article “Allocation Tracker for Android Performance Test (Android Studio)”.
Memory Monitor: obtains a dynamic view of Memory. Heap Viewer: displays what is stored in the Heap. 3) Allocation Tracker: specifies which code uses Memory
Use the MAT memory analysis tool
MAT: Memory Analyzer Tools, a tool that analyzes Java heap Memory in detail, so that it can analyze the details of Memory leaks.
Generate hprof file with AndroidStudio:
The generated Hprof file cannot be directly handed to MAT, since MAT cannot recognize other files, so we need to right click the file and convert it to one recognized by MAT.
Install MAT in Eclipse, then open the hprof file:
Use MAT to analyze the situation of memory leakage: 1. Find the operation of memory leakage according to the Total Size of data object; 2. 2. Find the object of memory leak (suspected object), that is, compare the Hprof file before and after the operation by MAT to locate the memory leak, which data object is the memory leak; 3, find the cause of the memory leak, that is, the object that holds the memory leak object found in step 2.
Specific steps: 1) Enter Histogram and filter out a certain suspected object category;
2) Analyze external objects that hold references to such objects;
3) Filtering out weak references, soft references, and virtual references because they can be killed by GC sooner or later is not a memory leak.
After filtering out, you need to enter the code to analyze whether the object’s reference holding is reasonable, and then solve the problem.
Memory optimization is generally divided into two aspects: one is to avoid writing code with memory leaks during development, and the other is to detect potential memory leaks with some memory analysis tools as described earlier. Let me take a look at some of the things we need to be aware of in our development.
Memory leaks caused by static variables
private static Context sContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
sContext = this;
}
Copy the code
The above code cannot be destroyed by the Activity because sContext references it.
Memory leaks caused by the singleton pattern
public class MyInstance {
private static MyInstance instance;
private Context context;
private MyInstance(Context context) {
this.context = context;
}
public static MyInstance getInstance(Context mcontext) {
if (instance == null) {
instance = new MyInstance(mcontext);
}
return instance;
}
public void setContext(Context context) { this.context = context; }}Copy the code
The singleton lifecycle is consistent with the Application. If you call getInstance in an Activity and pass in the Activity Context, the Activity object will be held by the singleton MyInstance, causing a memory leak. In fact, it is also a memory leak caused by static variables, because instance is a static variable. Static variables belong to static storage mode, and their storage space is the static data area in memory (allocated storage units in the static storage area), the data in this area has occupied these storage space during the entire running of the program (not released during the entire running of the program).
Non-static inner classes cause memory leaks
// Implicitly holds an Activity instance, activity.this. a public voidloadData(){
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
int b=a;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
Copy the code
There are also handlers that use the form of non-static inner classes:
private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); }};Copy the code
How do you solve the memory leak problem caused by non-static inner classes? This requires changing the static inner class to a static inner class, because static inner classes do not implicitly hold outer classes.
Private static Class MyHandler extends Handler{private static Class MyHandler extends Handler{private static class MyHandler extends Handler{private static class MyHandler extends Handler{private static class MyHandler extends Handler{private static class MyHandler extends Handler{ private WeakReference<MainActivity> mainActivity; public MyHandler(MainActivity mainActivity) { this.mainActivity = new WeakReference<MainActivity>(mainActivity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MainActivity main = mainActivity.get();if(main==null||main.isFinishing()){
return;
}
switch (msg.what){
case0: // Load data // reference mainactivity.this. a; int b = main.a;break; }}};Copy the code
In the above code, a static internal class is used to create a MyHandler that inherits Handler, and WeakReference is used internally. That is, WeakReference, if WeakReference is not used, mainActivity will directly hold a strong reference of an external class. Memory leaks result. In onDestroy invocation Handler removeCallbacksAndMessages best way.
@Override
protected void onDestroy() {
super.onDestroy();
MyHandler.removeCallbacksAndMessages(null);
}
Copy the code
Weak references mentioned above, we need to know about reference:
StrongReference (StrongReference) is never collected and terminates only when the JVM stops.
2) SoftReference (SoftReference) : when the memory is insufficient, it is reclaimed.
3) WeakReference: When garbage is collected, it is collected, and it terminates after GC.
4) PhatomReference: It is collected at garbage collection time and also terminates after GC.
Memory leaks caused by unclosed resources
Close the used resources, such as BroadCastReceiver, Cursor, Bitmap, IO streams, and customized AttributeSet, to prevent memory leaks. After the customized AttributeSet resource runs out, attrs.recycle() is called to recycle it. Otherwise, memory leaks may occur.
Memory leak caused by property animation
Property animations have a class of infinite loop animations, and if you don’t stop the animation in the onDestroy method, your Activity will cause a memory leak. Because if the animation is not stopped, the Activity’s View is held by the animation, which in turn holds the Activity, and the Activity cannot be released.
Unused listeners are not removed, resulting in memory leaks
public class ListenerCollector {
static private WeakHashMap<View, MyView.MyListener> sListener = new WeakHashMap<>();
public void setsListener(View view, MyView.MyListener listener) {
sListener.put(view, listener);
}
public static void clearListeners() {// Remove all listeners. sListener.clear(); }}Copy the code
The code above adds listeners to the process. After using the process, you need to call clearListeners in the onDestroy method to remove listeners. The feature of WeakHashMap is that if there is no reference to the key except for the reference of WeakHashMap, the map will automatically discard the value. View =null above, then the view in sListener will be discarded.