Common memory leaks under Android

 1. Static instance of non-static inner class

1.  public class MainActivity extends Activity  

 

2.  {  

 

3.      static Demo sInstance = null;  

 

4.      @Override  

 

5.      public void onCreate(BundlesavedInstanceState)  

 

6.      {  

 

7. super.onCreate (savedInstanceState);  

 

8.          setContentView(R.layout.activity_main);  

 

9.          if (sInstance == null)  

 

10.        {  

 

11.           sInstance= new Demo();  

 

12.        }  

 

13.    }  

 

14.    class Demo  

 

15.    {  

 

16.        voiddoSomething()  

 

17.        {  

 

18.           System.out.print("dosth.");  

 

19.        }  

 

20.    }  

 

21.}  

 

The sInstance instance type in the above code is a static instance. When the first instance of MainActivityact1 is created, sInstance will obtain and always hold the reference of act1. When MainAcitivity is destroyed and rebuilt, because sInstance holds a reference to act1, act1 cannot be recycled by GC. There will be 2 instances of MainActivity (act1 and the reconstructed MainActivity instance) in the process. This act1 object is a useless but always Objects that occupy memory, that is, garbage objects that cannot be collected. Therefore, for activities whose launchMode is not singleInstance, you should avoid instantiating static instances of their non-static inner classes in the activity.

 

2. Activity uses static members

 

1.  private static Drawable sBackground;    

 

2.  @Override    

 

3.  protected void onCreate(Bundle state) {    

 

4.      super.onCreate(state);    

 

6.      TextView label = new TextView(this);    

 

7.      label.setText("Leaks are bad");    

 

9.      if (sBackground == null) {    

 

10.        sBackground = getDrawable(R.drawable.large_bitmap);    

 

11.    }    

 

12.    label.setBackgroundDrawable(sBackground);    

 

14.    setContentView(label);    

 

15.}   

 

Since the drawable object is cached with the static member sBackground, the activity loads faster, but doing so is wrong. Because on the android 2.3 system, it will cause the activity to be destroyed and cannot be recycled by the system. The label.setBackgroundDrawable function call will assign the label to the member variable mCallback of sBackground. The above code means: sBackground (GC Root) will hold the TextView object, and TextView will hold the Activit object. Therefore, the Activity object cannot be recycled by the system.

 

The memory leaks in the above two examples are all because the life cycle of the Activity reference exceeds the life cycle of the activity object. That is, the Context leak is often said, because the activity is the context. 

 

To avoid context-related memory leaks, note the following:

 

Don't make long-term references to the activity's context (the lifetime of an activity's reference should be the same as the activity's lifetime)

 

If possible, try to use the context of the application instead of the context related to the activity

 

If the lifetime of an acitivity's non-static inner class is not controlled, then avoid using it; the correct way is to use a static inner class with a WeakReference to its outer class, like the inner class W in ViewRootImpl do that.

 

3. Memory problems when using handler

 

We know that Handler interacts with the main thread by sending Message. After Message is sent, it is stored in MessageQueue, and some Messages are not processed immediately. There is a target in the Message, which is a reference to the Handler. If the Message exists in the Queue for a longer time, the Handler cannot be recycled. If the Handler is non-static, the Activity or Service will not be recycled. Therefore, to properly handle inner classes such as Handler, you should define your own Handler as a static inner class.

 

The use of HandlerThread also requires attention:

 

  When we create a HandlerThread in the activity, the code is as follows:

 

1.  public class MainActivity extends Activity  

 

2.  {  

 

3.      @Override  

 

4.      public void onCreate(BundlesavedInstanceState)  

 

5.      {  

 

6. super.onCreate (savedInstanceState);  

 

7.          setContentView(R.layout.activity_main);  

 

8.         Thread mThread = newHandlerThread("demo", Process.THREAD_PRIORITY_BACKGROUND);   

 

9.          mThread.start();  

 

10.        MyHandler mHandler = new MyHandler( mThread.getLooper( ) );  

 

11.         …….  

 

12.         …….  

 

13.         …….  

 

14.     }  

 

15.    @Override  

 

16.    public void onDestroy()  

 

17.    {  

 

18. super.onDestroy ();  

 

19.    }  

 

20.}  

 

There is a leakage problem in this code, because the run method of HandlerThread is an infinite loop, it will not end by itself, and the life cycle of the thread exceeds the life cycle of the activity. When the horizontal and vertical screens are switched, the number of HandlerThread threads will increase with the number of activity reconstructions. Increase.

 

The thread should be stopped at onDestroy: mThread.getLooper().quit();

 

In addition, for threads that are not HandlerThread, you should also ensure that the thread has terminated after the activity is consumed. You can do this: call mThread.join() in onDestroy;

 

4. After registering an object, it is not deregistered

 

Register broadcast receivers, register observers, etc., such as:

 

Suppose we want to monitor the phone service in the system to get some information (such as signal strength, etc.) in the lock screen interface (LockScreen), we can define a PhoneStateListener object in LockScreen and register it in the TelephonyManager service. For the LockScreen object, a LockScreen object is created when the lock screen interface needs to be displayed, and the LockScreen object is released when the lock screen interface disappears. But if you forget to cancel the PhoneStateListener object we registered before when releasing the LockScreen object, it will cause the LockScreen to not be reclaimed by the GC. If the lock screen interface is continuously displayed and disappeared, it will eventually cause OutOfMemory because a large number of LockScreen objects cannot be recycled, causing the system_process process to hang up.

 

5. Memory leaks caused by objects in the collection not being cleaned up

 

  We usually add some object references to the collection, when we don't need the object, if we don't clean up its references from the collection, the collection will grow bigger and bigger. If the collection is static, then the situation is even more serious.

 

6. Memory leaks caused by resource objects not being closed

 

  Resource objects such as (Cursor, File files, etc.) often use some buffers. When we are not using them, we should close them in time so that their buffers can reclaim memory in time. Their buffers exist not only within the Java Virtual Machine, but also outside the Java Virtual Machine. If we just set its references to null without closing them, it will often cause memory leaks. Because some resource objects, such as SQLiteCursor (in the destructor finalize(), if we don't close it, it will call close() to close it by itself), if we don't close it, the system will also close it when recycling it, but This efficiency is too low. Therefore, when the resource object is not in use, its close() function should be called immediately to close it, and then set to null. When our program exits, we must ensure that our resource object has been closed.

 

  In the program, the operation of querying the database is often performed, but there are often cases where the Cursor is not closed after use. If our query result set is relatively small, the memory consumption is not easy to be found, and the memory problem will only be reproduced in the case of a long time and a large number of operations, which will bring difficulties and risks to future testing and troubleshooting.

 

7. Some bad code becomes memory pressure

 

Some codes do not cause memory leaks, but they either do not release unused memory effectively and in time, or do not use existing objects effectively but frequently apply for new memory, causing serious damage to memory recycling and allocation. It is easy to force the virtual machine to allocate more memory to the application process, increase the burden on the vm, and cause unnecessary memory expenses.

 

7.1 Improper use of Bitmap

 

   First, timely destruction.

 

Although, the system can confirm that the memory allocated by Bitmap will eventually be destroyed, but because it occupies too much memory, it is likely to exceed the limit of the Java heap. Therefore, when you run out of Bitmap, you should recycle it in time. Recycle does not guarantee that the Bitmap will be released immediately, but it will give the virtual machine a hint: "The picture 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, but only need to record a reduced image. At this time, a certain sampling rate can be set, which can greatly reduce the memory occupied. Such as the following code:

 

1.  private ImageView preview;    

 

2.  BitmapFactory.Options options = newBitmapFactory.Options();    

 

3. options.inSampleSize = 2;//The width and height of the picture are half of the original, that is, the picture is a quarter of the original    

 

4. Bitmap bitmap =BitmapFactory.decodeStream(cr.openInputStream(uri), null, options); preview.setImageBitmap(bitmap);   

 

Third, clever use of soft references (SoftRefrence)

 

Sometimes, after we use Bitmap, we don't keep a reference to it, so we can't call the Recycle function. At this time, the clever use of soft references can effectively release the Bitmap when the memory is running low. as follows:

 

1.  SoftReference<Bitmap>  bitmap_ref  = new SoftReference<Bitmap>(BitmapFactory.decodeStream(inputstream));   

 

2.  ……  

 

3.  ……  

 

4.  if (bitmap_ref .get() != null)  

 

5.       bitmap_ref.get().recycle();  

 

7.2 When constructing the Adapter, the cached convertView is not used

 

  Taking the BaseAdapter that constructs ListView as an example, the methods are mentioned in BaseAdapter:

 

public View getView(intposition, View convertView,ViewGroup parent)

 

  To provide ListView with the view object required by each item. Initially, ListView will instantiate a certain number of view objects from BaseAdapter according to the current screen layout, and ListView will cache these view objects. When the ListView is scrolled up, the view object of the top list item is recycled and used to construct the new bottom list item. This construction process is completed by the getView() method. The second parameter View convertView of getView() is the view object of the cached list item (when there is no view object in the cache during initialization, convertView is null).

 

  It can be seen from this that if we do not use convertView, but re-instantiate a View object in getView() every time, it will waste time and cause memory garbage, which will increase the pressure on garbage collection. If garbage collection is too late If so, the virtual machine will have to allocate more memory to the application process, causing unnecessary memory overhead. The process of ListView recycling the view object of the list item can be viewed:

 

android.widget.AbsListView.Java--> voidaddScrapView(View scrap) 方法。

 

1.  public View getView(int position, View convertView, ViewGroupparent) {  

 

2.      View view = newXxx(...);  

 

3.      return view;  

 

4.  }  

 

  Corrected sample code:

 

1.  public View getView(intposition, View convertView, ViewGroup parent) {  

 

2.  View view = null;  

 

3.  if (convertView != null){  

 

4.      view = convertView;  

 

5.      populate(view, getItem(position));  

 

6.  } else {  

 

7.      view = new Xxx(...);  

 

8.  }  

 

9.  return view;  

 

10.}  

 

7.3 Do not create objects in frequently called methods, especially taboo creating objects in loops. Appropriately use hashtable, vector to create a set of object containers, and then fetch those objects from the container, instead of discarding them after each new.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326400041&siteId=291194637