Android: Memory Optimization details.

Source: Internet
Author: User
Tags sqlite database
Due to the special nature of Android systems, the installed software is installed in the memory by default, so as users install more and more software, the memory available for running programs is getting smaller and smaller, this requires that we use as little memory as possible when developing Android programs. Based on my personal development experience, I have summarized the following methods to optimize the memory:

  1. If an object obtained by creation or other methods is no longer used, it is automatically set to null.
  2. Try to zoom in or out or flip images in the program. The memory occupied by image operations may be larger than the image itself.
  3. Try to put some static objects (especially set objects) in the SQLite database. Use SQL statements to search and match the data.
  4. Some connection resources should be released if they are not used, such as input and output streams of Database Connection Files. Avoid releasing in special circumstances (such as exceptions or other circumstances)
  5. Some long-period Objects Reference short-period objects, but these short-period objects may only be used within a small range. Therefore, this risk should also be cleared during memory check.
  6. An object is referenced by multiple objects, but only one object is released. This object may not be released.

 

 

 

I. Android memory mechanism

Android programs are written in Java, so the memory management of Android is similar to that of Java. The programmer allocates memory for the object through new, and all objects are allocated space in the Java heap. However, the release of the object is done by the garbage collector. In C/C ++, the memory mechanism is "Who is polluted and who is responsible for governance". Java is more user-friendly and a dedicated garbage collector (GC) is invited for us ).

How can GC check whether an object has been deprecated? Java adopts the principle of Directed Graphs. Java considers the reference relationship as directed edges of a graph, and directed the directed edge from the quotor to the referenced object. A thread object can be used as the starting vertex of a directed graph. This graph is a tree starting from the starting vertex. All objects that can be reached by the root vertex are valid objects and GC will not recycle these objects. If an object (connected subgraph) is inaccessible to this root vertex (note that this graph is a directed graph), we think this (these) object is no longer referenced and can be recycled by GC.

Ii. Android memory overflow

How does Android memory overflow occur?

The android virtual machine is a register-based Dalvik. Its maximum heap size is generally 16 m, and some machines are 24 m. Therefore, the memory space we can use is limited. If our memory usage exceeds a certain level, an outofmemory error occurs.

Why is memory insufficient? I think there are two main reasons:

  • Due to program errors, some resources (such as context) can be referenced for a long time, resulting in Memory leakage and unreleased resources.
  • Saves multiple objects (such as Bitmap) that consume too much memory, resulting in memory exceeding the limit.

3. Static

Static is a keyword in Java. When it is used to modify a member variable, the variable belongs to the class, rather than the instance of the class. Therefore, the life cycle of a variable modified with static is very long. If you use it to reference some instances that consume too much resources (the case of context is the most), you should be cautious.

 
 
  1. Public class classname {
  2. Private Static Context mcontext;
  3. // Omitted
  4. }

The above code is very dangerous, if the activity is assigned to mcontext. Even if the activity has been ondestroy, the activity will not be released because there are still objects that store its reference.

Let's take an example in the android document.

 
 
  1. private static Drawable sBackground;  
  2.      
  3.  @Override  
  4.  protected void onCreate(Bundle state) {  
  5.    super.onCreate(state);  
  6.      
  7.    TextView label = new TextView(this);  
  8.    label.setText("Leaks are bad");  
  9.      
  10.    if (sBackground == null) {  
  11.      sBackground = getDrawable(R.drawable.large_bitmap);  
  12.    }  
  13.    label.setBackgroundDrawable(sBackground);  
  14.      
  15.    setContentView(label);  
  16.  }  

Sbackground is a static variable, but we found that we did not explicitly Save the reference of contex. However, when drawable is connected to view, drawable sets the view as a callback. Because the view contains the reference of context, we still save the reference of context. The reference chain is as follows:

Drawable-> textview-> Context

Therefore, the context is not released, and memory leakage occurs.

How can we effectively avoid such a reference?

First, we should try our best to avoid using static member variables to reference instances that consume too much resources, such as context.

Second, use the application context whenever possible. Because the application context has a long life cycle, it will not cause memory leakage if referenced.

Third, use weakreference instead of strong reference. For example, you can use weakreference <context> mcontextref;

For details about this part, refer to the article in the android document.

4. Thread-caused fault

Threads are also an important source of Memory leakage. The main cause of thread Memory leakage is the uncontrollable thread lifecycle. Let's consider the following code.

 
 
  1. public class MyActivity extends Activity {  
  2.     @Override  
  3.     public void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         setContentView(R.layout.main);  
  6.         new MyThread().start();  
  7.     }  
  8.   
  9.     private class MyThread extends Thread{  
  10.         @Override  
  11.         public void run() {  
  12.             super.run();  
  13.             //do somthing  
  14.         }  
  15.     }  
  16. }  

This code is usually very simple and is often used. Let's think about a problem: assume that the run function of mythread is a very time-consuming operation. When we enable this thread, we change the horizontal screen of the device to a vertical screen, generally, when the screen is switched, the activity will be re-created. According to our ideas, the old activity should be destroyed. However, this is not the case.

Because our thread is an internal class of activity, a reference of activity is saved in mythread. When the run function of mythread is not completed, mythread will not be destroyed, therefore, the old activity referenced by it will not be destroyed, so Memory leakage occurs.

 

Some people like to use asynctask provided by Android, but in fact asynctask is more serious. This memory leakage problem occurs only when the run function does not end, however, the internal implementation mechanism of asynctask is to use threadpoolexcutor. the life cycle of the thread object generated by this class is uncertain and cannot be controlled by the application. Therefore, if asynctask is used as the internal class of the activity, it is more prone to memory leakage.

How should we solve the memory leakage caused by such threads?

First, change the internal class of the thread to the static internal class.

Second, use weak references within the thread to save context references.

The solution model is as follows:

 
 
  1. public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends  
  2.         AsyncTask<Params, Progress, Result> {  
  3.     protected WeakReference<WeakTarget> mTarget;  
  4.   
  5.     public WeakAsyncTask(WeakTarget target) {  
  6.         mTarget = new WeakReference<WeakTarget>(target);  
  7.     }  
  8.   
  9.     /** {@inheritDoc} */  
  10.     @Override  
  11.     protected final void onPreExecute() {  
  12.         final WeakTarget target = mTarget.get();  
  13.         if (target != null) {  
  14.             this.onPreExecute(target);  
  15.         }  
  16.     }  
  17.   
  18.     /** {@inheritDoc} */  
  19.     @Override  
  20.     protected final Result doInBackground(Params... params) {  
  21.         final WeakTarget target = mTarget.get();  
  22.         if (target != null) {  
  23.             return this.doInBackground(target, params);  
  24.         } else {  
  25.             return null;  
  26.         }  
  27.     }  
  28.   
  29.     /** {@inheritDoc} */  
  30.     @Override  
  31.     protected final void onPostExecute(Result result) {  
  32.         final WeakTarget target = mTarget.get();  
  33.         if (target != null) {  
  34.             this.onPostExecute(target, result);  
  35.         }  
  36.     }  
  37.   
  38.     protected void onPreExecute(WeakTarget target) {  
  39.         // No default action  
  40.     }  
  41.   
  42.     protected abstract Result doInBackground(WeakTarget target, Params... params);  
  43.   
  44.     protected void onPostExecute(WeakTarget target, Result result) {  
  45.         // No default action  
  46.     }  
  47. }  



In fact, the thread problem is not only the memory leakage, but also some catastrophic problems. This article does not discuss memory issues.

 

Because 51cto won't let me finish it once, I say that I have too many words, so I passed it separately.

5. Super fat bitmap

It can be said that the vast majority of people who encounter the outofmemory problem are due to the bitmap problem. Because bitmap occupies too much memory, it is a "super fat man", especially a high-resolution image. If you want to display multiple images, the problem is even more significant.

How can we solve the memory problems brought by bitmap?

1. Timely destruction.

Although the system can confirm that the memory allocated by bitmap will eventually be destroyed, it may exceed the Java heap limit because it occupies too much memory. Therefore, when using bitmap, You need to delete the recycle in time. Recycle is not sure that bitmap will be released immediately, but it will imply to the Virtual Machine: "The image can be released ".

Second, set a certain sampling rate.

Sometimes, the area we want to display is very small and it is not necessary to load the entire image. Instead, we only need to record a reduced image. At this time, we can set a certain sampling rate, therefore, the occupied memory can be greatly reduced. The following code:

 
 
  1. Private imageview preview;
  2. Bitmapfactory. Options = new bitmapfactory. Options ();
  3. Options. insamplesize = 2; // The image width and height are 1/2 of the original image, that is, the image is 1/4 of the original image.
  4. Bitmap bitmap = bitmapfactory. decodestream (Cr. openinputstream (URI), null, options );
  5. Preview. setimagebitmap (Bitmap );

Third, use softrefrence)

Sometimes, we do not retain references to bitmap, so we cannot call the recycle function. By using soft references, bitmap can be effectively released when the memory is insufficient. For example:

 
 
  1. /** This example is written by the blogger to describe the usage without verification */
  2. Private class myadapter extends baseadapter {
  3. Private arraylist <softreference <bitmap> mbitmaprefs = new arraylist <softreference <bitmap> ();
  4. Private arraylist <value> mvalues;
  5. Private context mcontext;
  6. Private layoutinflater minflater;
  7. Myadapter (context, arraylist <value> values ){
  8. Mcontext = context;
  9. Mvalues = values;
  10. Minflater = (layoutinflater) Context. getsystemservice (context. layout_inflater_service );
  11. }
  12. Public int getcount (){
  13. Return mvalues. Size ();
  14. }
  15. Public object getitem (int I ){
  16. Return mvalues. Get (I );
  17. }
  18. Public long getitemid (int I ){
  19. Return I;
  20. }
  21. Public View getview (int I, view, viewgroup ){
  22. View newview = NULL;
  23. If (view! = NULL ){
  24. Newview = view;
  25. } Else {
  26. Newview = (View) minflater. Inflate (R. layout. image_view, false );
  27. }
  28. Bitmap bitmap = bitmapfactory. decodefile (mvalues. Get (I). filename );
  29. Mbitmaprefs. Add (New softreference <bitmap> (Bitmap); // Add arraylist here
  30. (Imageview) newview). setimagebitmap (Bitmap );
  31. Return newview;
  32. }
  33. }

6. Unusual cursor

Cursor Is a class used to manage data sets after data is queried by Android. Normally, if the queried data volume is small, there will be no memory problems, moreover, the virtual machine can ensure that the cusor will be released eventually.

However, if the data size of the cursor table is large, especially if blob information exists, the memory occupied by the cursor should be promptly released, rather than waiting for GC to process. In addition, Android obviously prefers programmers to manually close the cursor, because in the source code, we find that if the garbage collector is used for collection, an error will be prompted to the user.

Therefore, the method of using cursor is generally as follows:

 
 
  1. Cursor cursor = null;  
  2. try {  
  3.     cursor = mContext.getContentResolver().query(uri,null, null,null,null);  
  4.     if(cursor != null) {  
  5.         cursor.moveToFirst();  
  6.         //do something  
  7.     }  
  8. } catch (Exception e) {  
  9.     e.printStackTrace();    
  10. } finally {  
  11.     if (cursor != null) {  
  12.        cursor.close();  
  13.     }  
  14. }  

In one case, we cannot directly close cursor, which is applied in cursoradapter. But note that cursoradapter does not automatically close cursor at the end of acivity, therefore, you need to manually disable it in the ondestroy function.

 
 
  1. @Override  
  2. protected void onDestroy() {        
  3.     if (mAdapter != null && mAdapter.getCurosr() != null) {  
  4.         mAdapter.getCursor().close();  
  5.     }  
  6.     super.onDestroy();   
  7. }  

The changecursor function in the cursoradapter will release the original cursor and replace it with the new cursor, so you don't have to worry that the original cursor is not closed.

You may think of using activity managedquery to generate cursor, so that the life cycle of cursor will be consistent with that of acitivity. What a perfect solution! However, managedquery also has many limitations.

The cursor generated by managedquery must not be replaced, because many programs may not have certain query conditions. Therefore, we often use the new query cursor to replace the original cursor. Therefore, this method has a small scope of application.

7. other things to be said.

In fact, there are still many methods and requirements to reduce memory usage. For example, do not use the entire image. Try to use a 9path image. The adapter needs convertview, and so on. Many details can save memory. These all need to be mined. Who is called Android memory.

Due to the special nature of Android systems, the installed software is installed in the memory by default, so as users install more and more software, the memory available for running programs is getting smaller and smaller, this requires that we use as little memory as possible when developing Android programs. Based on my personal development experience, I have summarized the following methods to optimize the memory:

  1. If an object obtained by creation or other methods is no longer used, it is automatically set to null.
  2. Try to zoom in or out or flip images in the program. The memory occupied by image operations may be larger than the image itself.
  3. Try to put some static objects (especially set objects) in the SQLite database. Use SQL statements to search and match the data.
  4. Some connection resources should be released if they are not used, such as input and output streams of Database Connection Files. Avoid releasing in special circumstances (such as exceptions or other circumstances)
  5. Some long-period Objects Reference short-period objects, but these short-period objects may only be used within a small range. Therefore, this risk should also be cleared during memory check.
  6. An object is referenced by multiple objects, but only one object is released. This object may not be released.
Related Article

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.