Android memory leaks

Source: Internet
Author: User

In the sharing meeting to listen to the small partners on this part of the content has been explained, found that in peacetime programming there are many problems did not notice, so recorded to share to you, but also welcome you to correct the shortcomings of the text.


Memory leaks and memory overflow:

A memory overflow simply means that the program requires more memory than the virtual function provides, causing the program to crash, which is our common out of memory error.

A memory leak refers to a program failing to release memory that is no longer in use. Memory leaks do not mean that there is physical disappearance, but the application allocates a certain memory, due to the design of the error, resulting in the release of the memory before the memory loss of control, resulting in a waste of memory. A small amount of memory leaks does not affect the running of the program, but the long accumulation consumes more and more memory, resulting in a memory overflow.

The allocation of memory is done by the program, and the release of memory is done by a GC (garbage collection mechanism). In order to properly dispose of objects, the GC must monitor the running state of each object, including the object's application, references, references, assignments, and so on. This object can be reclaimed when an object is detected as completely useless.

  
Common memory leaks:
Understanding the above concepts, we will enumerate a few of the bad programming habits that are prone to memory leaks in our usual situations, and use the memory analysis tool that comes with Android Studio to detect memory leaks.

    • Single-Instance memory leak
    • Memory leaks caused by collection classes
    • Memory leaks caused by non-static internal classes
    • Anonymous internal class/async thread causes memory leak
    • Handler causing a memory leak

① a single case of memory leaks:

Because of its static characteristics, the single case has the same long life cycle as the application, which is prone to memory leaks due to improper handling.
For example, we often initialize some of the application's open screen pages, such as resource reading, network requests, and other single-instance methods. Let's simulate a scenario like this:
Create a tool class to read the drawable resource and use the singleton design pattern.

 Public  class resourcereader {    //Singleton object    Private StaticResourceReader minstance =NULL;PrivateContext context;//Create objects through context contexts    Private ResourceReader(Context context) { This. Context = Context; } Public StaticResourceReadergetinstance(Context context) {if(Minstance = =NULL) {minstance =NewResourceReader (context); }returnMinstance; } PublicDrawablegetdrawable(intDrawableid) {returnContextcompat.getdrawable (context, Drawableid); }}

In Welcomeactivity, the tool class reads a picture, jumps mainactivity after the button is clicked, and welcomeactivity finishes off.

 Public  class welcomeactivity extends appcompatactivity {    PrivateImageView ImageView;@Override    protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Setcontentview (R.layout.activity_welcome); This. ImageView = (ImageView) Findviewbyid (r.id.welcome_image);//Read a drawable resource by tool classdrawable drawable = resourcereader.getinstance ( This). Getdrawable (R.drawable.welcome);    Imageview.setimagedrawable (drawable); } Public void OnClick(View view) {Intent Intent =NewIntent ( This, Mainactivity.class);        StartActivity (Intent); Finish ();//Close the activity}}

A drawable resource is still loaded with the tool class in Mainactivity.

publicclass MainActivity extends AppCompatActivity {    private ImageView imageView;    @Override    protectedvoidonCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Drawable drawable = ResourceReader.getInstance(this).getDrawable(R.drawable.main);        imageView = (ImageView) findViewById(R.id.main_image);        imageView.setImageDrawable(drawable);    }}

The results are as follows:




While debugging is actually running, Android Studio is already recording some real-time information on the debug device, opening the montiors of Android Monitor to see the following interface



We can click on the ② button for a short period of time after clicking the ③ button (dump Java heap), because the point ② will let our device initiate a GC recycle operation, recycling those useless objects, because these useless objects are not within our consideration.
After you finish the ② button, Studio starts to work on its own, wait a moment. When the dump succeeds, the Hprof file is generated and automatically opened, and the file name is process timestamp.


This figure is provided by netizens

Next we click on the right analyzer Tasks to expand, and the Perform Analyzer button will see the results of the automated analysis by Studio for us later.



Because our code is relatively simple, here can be very intuitive to see the activity of our memory leaks, in the more complex code case we can also combine MAT to use, can show more intuitive results, here is no longer detailed.

Now let's analyze the cause of the welcomeactivity memory leak:
When we call drawable Load tool class in welcomeactivity, we pass in its own context so that ResourceReader's static object has a reference to welcomeactivity, after we have used the welcomeactivity and call the Finish () method, we think it has been destroyed and the memory can be recycled, in fact, because its referenced GC system can not reclaim this memory and we also lost control of this memory, which led to welcomeactivity memory leak.

Workaround:
① we eliminate a single reference to an Activity when it is destroyed. This approach is limited and not all situations are appropriate. For example, a non-static property exists in a class, and a call at a different time may cause its value to be garbled.
Add the following code to the ResourceReader tool class:

publicvoidreset(){        ifnull){            null;            null;        }    }

Call the new addition method in the Activity's Destroy method:

@OverrideprotectedvoidonDestroy() {      ResourceReader.getInstance(this).reset();      super.onDestroy();     }

② in a singleton, we can refer to objects with longer lifecycles, such as application (recommended), with less change, just change the Context to ApplicationContext.

publicstaticgetInstance(Context context){        ifnull){            //将 Context 改为 ApplicationContext            new ResourceReader(context.getApplicationContext());        }        return mInstance;    }

Once the modifications are complete, we run the program again to see the results:




And look at the analysis of our analyzer Tasks.





② the collection class causes a memory leak:

If a collection is a global variable of a class, it is most likely that the collection will consume more memory if the variable does not have a corresponding delete mechanism.
Simulate a scenario where a list of Bitmap is added to an image after an operation, but because of a design flaw the object does not have a mechanism to delete the element.

 Public  class gatheractivity extends appcompatactivity {    Private Static FinalList<bitmap> bitmaplist =NewArraylist<> ();PrivateTextView TextView;@Override    protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate);        Setcontentview (R.layout.activity_gather);    TextView = (TextView) Findviewbyid (R.id.list_numer); } Public void OnClick(View view) {if(View.getid () = = R.id.btn_add) {//Join bitmapBitmaplist.add (Bitmapfactory.decoderesource (Getresources (), r.drawable.welcome)); } Textview.settext (String.Format ("Total of%d elements", Bitmaplist.size ())); }@Override    protected void OnDestroy() {LOG.V ("YGL","Gather Activity on Destroy");Super. OnDestroy (); }}


Workaround:
① The final static modifier must be used with caution.
② The collection must be deleted at a specific time, or emptied, or dumped locally, avoiding unlimited growth in the collection's memory.



③ a non-static inner class causes a memory leak:

This is often overlooked by us, the non-static inner class will be holding a reference to the external class by default, and the non-static inner classes have created a static instance that would cause a memory leak if no reasonable release.

 Public  class nearactivity extends appcompatactivity {    //non-static internal class User-created static instance Muser    Private StaticUser Muser =NULL;@Override    protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate);        Setcontentview (r.layout.activity_near); Muser =NewUser (); }@Override    protected void OnDestroy() {LOG.V ("YGL","near Activity on Destroy");Super. OnDestroy (); } class user{PrivateString name;Private intAge }}

We can conclude through the above analysis that the memory is not recycled after the nearactivity is destroyed.



Workaround:
① to destroy the static objects of the inner class at the appropriate time, such as:

@Override    protectedvoidonDestroy() {        Log.v("ygl","Near Activity On Destroy");        ifnull){            null;        }        super.onDestroy();    }

② defines an inner class as a static inner class so that it does not establish a relationship with an external class.



④ Anonymous internal class/async thread causes a memory leak:

An anonymous inner class holds a reference to an external class that, if passed on to an asynchronous thread, is no longer the same as the life cycle of the outer class, which can result in an external class object memory leak.
Take a scenario that we often use:

 Public  class syncactivity extends appcompatactivity {    @Override    protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Setcontentview (R.layout.activity_sync);//Create anonymous inner class        NewThread (NewRunnable () {@Override             Public void Run() { for(intI=0;i< +; i++) {Try{Thread.Sleep ( +); LOG.V ("YGL","i="+i); }Catch(Exception e) {}}}}). Start ();//Destroy activityFinish (); }@Override    protected void OnDestroy() {LOG.V ("YGL","Sync Activity on Destroy");Super. OnDestroy (); }}

As you may have guessed, the child thread will continue to execute after the activity is destroyed, while the inner class new Runnable () {}; Having a reference to the activity in the external category causes the memory of the activity to not be recycled.

Workaround:
① interrupts the operation of a child thread in OnDestroy if it is a thread that is not necessary to run after the Activity has ended.
② can consider using a global thread pool instead of declaring child threads in a class.


⑤handler causes a memory leak:

The Handler life cycle and activity are inconsistent, and when activity is finish, a Message that delays the execution of the task continues to occur in the main thread, which holds the Handler reference to the activity, causing the activity to not be Recovery.

 Public  class sampleactivity extends Activity {   Private FinalHandler Mhandler =NewHandler () {@Override       Public void Handlemessage(Message msg)   {         ...      } }@Override   protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Mhandler.postdelayed (NewRunnable () {@Override           Public void Run() {              ...      } }, +* -*Ten);   Finish (); }}


Workaround:
① can empty unnecessary message messages at the end of Activity
② uses a combination of static inner classes and weak references



Summarize:

    • References to components such as activity should be controlled during the activity's life cycle, and if not, consider using ApplicationContext to avoid the activity being referenced by an external minister's life cycle object.
    • Try not to use non-static external member variables in static variables or static internal classes, even if you must use them, to empty the external member variables at the appropriate time.
    • Handler can empty the message inside the Handler when the resource is released.
    • Some of the objects that make up the memory are best able to be released voluntarily after use, such as bitmap.recycle (), emptying the array, and so on.
    • For a variety of network streams, file flow, etc. to be closed in a timely manner.
    • It is prudent to consider the more sensitive global collections of single static objects.

Android memory leaks

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.