Android performance optimization memory leak

Android performance optimization memory leak

Overview

A memory leak is when a program fails to release memory that is no longer in use due to negligence or error. In Android, when an object holds a reference to an Activity, if the object cannot be recycled by the system, then when the Activity is no longer in use, the Activity will not be recycled by the system, and a memory leak will occur. A memory leak once or twice in an application will not have any impact, but after a long period of use, if there are a large number of Activities that cannot be recycled by GC, it will eventually lead to OOM. Let's analyze the common factors that lead to memory leaks and how to detect memory leaks.

Common factors that cause memory leaks

Scenario 1: Static Activity and View

Static variables Activity and View can cause memory leaks. In the following code, the Activity's Context and TextView are set as static objects, resulting in a memory leak.

  1. import android.content.Context;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.widget.TextView;
  5.   
  6. public class MainActivity extends AppCompatActivity {
  7.   
  8. private static Context context;
  9. private static TextView textView;
  10.   
  11. @Override
  12. protected void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.activity_main);
  15. context = this;
  16. textView = new TextView(this);
  17. }
  18. }

Scenario 2: Thread, anonymous class, inner class

In the following code, there is a non-static anonymous class object Thread, which implicitly holds a reference to an external class LeakActivity, thus causing a memory leak. Similarly, if this Thread is an inner class of LeakActivity instead of an anonymous inner class, it will also hold a reference to the external class and cause a memory leak. Here, you only need to define the Thread anonymous class as a static inner class (a static inner class will not hold an implicit reference to the external class).

  1. public class LeakActivity extends AppCompatActivity {
  2.   
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_leak);
  7. leakFun();
  8. }
  9.   
  10. private void leakFun(){
  11. new Thread(new Runnable() {
  12. @Override
  13. public void run() {
  14. try {
  15. Thread.sleep( Integer .MAX_VALUE);
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. });
  21. }
  22. }

Scenario 3: Animation

There is a type of infinite loop animation in attribute animation. If you play this type of animation in an Activity and stop the animation in onDestroy, the animation will continue to play. At this time, the Activity will be held by the View, which will prevent the Activity from being released. To solve this problem, you need to call objectAnimator.cancel() in onDestroy in the Activity to stop the animation.

  1. public class LeakActivity extends AppCompatActivity {
  2.   
  3. private TextView textView;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_leak);
  8. textView = (TextView)findViewById(R.id.text_view);
  9. ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(textView, "rotation" ,0,360);
  10. objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
  11. objectAnimator.start();
  12. }
  13. }

Scenario 4: Handler

The memory leak of Handler has been introduced in detail in the article (Android message mechanism - Handler working process) [http://blog.csdn.net/ljd2038/article/details/50889754], so I will not repeat it here.

Scenario 5: Improper use of third-party libraries

For the use of some third-party open source frameworks such as EventBus and RxJava, if the subscription is not unsubscribed before the Activity is destroyed, memory leaks will occur.

Detecting memory leaks using MAT

After introducing common memory leaks, let's take a look at using MAT (Memory Analysis Tool) to detect memory leaks. The download address of MAT is: http://www.eclipse.org/mat/downloads.php.

Let's look at a piece of erroneous code that will cause a memory leak.

  1. public class LeakActivity extends AppCompatActivity {
  2.   
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_leak);
  7. EventBus.getDefault().register(this);
  8. }
  9.   
  10. @Subscribe
  11. public void subscriber(String s){
  12.   
  13. }
  14. }

In the above code, there is a memory leak because EventBus is not unregistered. Let's take this code as an example to see how to analyze memory leaks.

Open Monitors in AndroidStudio and you can see the following interface.

Here we can see that when the app is just started, the memory occupied is 15M. Then we start to operate the app and repeatedly enter and exit LeakActicity. Click the GC button as shown above. Now we look at the memory usage.

Here we can see that the memory has been increasing continuously and has reached 33M, and it cannot be recovered by GC. So we can judge that there must be a memory leak at this time. Now click the Dump Java Heap button again, and you can see the generated hprof file in the captures window. But the hprof file generated at this time is not in a standard format. We need to convert it through the tool hprof-conv provided by the SDK. The tool is in the platform-tools directory of the SDK. The execution command is as follows:

  1. hprof-conv XXX.hprof converted-dump.hprof

Of course, this step can be omitted in AndroidStudio, and the hprof file in standard format can be directly exported.

At this time, you can use the MAT tool to open the exported hprof file. The opening interface is as shown below:

The most commonly used tools in MAT are Histogram and Dominator Tree, which correspond to the A and B buttons in the figure above. Histogram can show the number of different types of buffers in memory and the size of the memory they occupy, while Dominator Tree sorts the objects in memory from large to small and can analyze the reference relationship between objects. Here we will introduce the meaning of the two symbols in MAT.

  • ShallowHeap: The memory size occupied by the object itself, excluding the objects it references
  • RetainedHeap: The memory size of the object itself plus the size of the objects it directly or indirectly references

Histogram

Since memory leaks in Android generally occur in Acivity, you can click the Histogram button and search for Activity.

Here we can see that there are 69 objects in LeakActivity, which basically indicates that there is a memory leak. At this time, we can analyze it by looking at the reference chain of the GC object. Right-click and select Merge Shortest paths to GC Roots and select exclude weak/soft references to exclude weak and soft references.

After excluding soft references and weak references, the following figure is shown:

Here we can see the LeakActivity memory leak caused by EventBus.

In the Histogram, you can also view which objects an object contains references to. For example, to view the references contained in LeakActivity, you can right-click and select with incoming reference in list objects. And with outcoming reference means that the selected object holds references to those objects.

Dominator Tree

Now we can click the Dominator Tree button and search for Activity. You can see the following picture:

Here you can see a lot of LeakActivity. Then right-click and select Path To GC Roots->exclude weak/soft references to exclude weak references and soft references.

After that, you can see the following results, which is still the memory leak caused by EventBus:

Summarize

Memory leaks are often ignored by us, but when a large amount of memory leaks lead to OOM, the impact it causes cannot be underestimated. Of course, in addition to the above analysis of memory leaks, we can also use LeakCanary to analyze memory leaks. The use of LeakCanary will not be introduced in detail here.

<<:  The first issue of Aiti Tribe: Spark offline analysis dimensions

>>:  Weird Java question: Why does 128 == 128 return False, but 127 == 127 returns True?

Recommend

The world's largest gambling city: I advise you not to gamble

today Let's go to Las Vegas, known as the &qu...

Clothing wholesale WeChat applet, how to develop clothing WeChat applet?

Q: How to develop a WeChat applet for clothing wh...

Jianfang 3L Strategy Practice Class 2021

Kong Qinlue practical class Momentum main line + ...

Do you still remember China’s “best tasting vaccine”?

On March 26, 1953, the first polio vaccine was su...

Tips for reducing lead costs by advertising in the education industry!

In the homogeneous industry competition, how can ...

TikTok’s advertising types and placements

TikTok is now well known to many domestic sellers...