Memory leaks--contentview cache usage with listview optimization

Source: Internet
Author: User

There are a number of reasons why Android memory leaks, listed below, will be addressed in the future

1. No cache Convertview (derived from ListView optimization problem) when constructing adapter

2. Query database cursor is not closed

3. Activity life cycle object is greater than activity life cycle (about application context and activity context)

4, Bitmap object is not used when not recycle off (there are other solutions)

Today is the first one: how to use caching to optimize a ListView

Because if the cache Convertview is not used, the view is recreated each time the GetView is called, so that the previous view may not have been destroyed, and the constant new view will inevitably cause a memory leak.

There are 3 scenarios when using GetView: (1) not using Convertview, (2) using Convertview, (3) using convertview+ static class Viewholder

I did a test, the code below, create 2000 view, from 0 to the end, calculate the total consumption, while showing the size of the GC free memory, the results of three tests are as follows:

Note: Here first said Gc_external_alloc freed 7K, 18% free 11153k/13511k, EXTERNAL 1632k/1672k, paused 89ms meaning

In Dalvik, the memory allocated for a program varies depending on the model, typically 32M, while the virtual machine allocates the memory to the heap memory (heap) used by Java and the memory used by Nativie (external) (That is, the memory allocated by malloc in the virtual machine in a class called local Nativie through JNI, such as Bitmap,java.nio.bytebuffers). However, the two different sharing, that is, native memory is not enough, and Java memory is not available to Java application, you must apply to the virtual machine, when the virtual machine can not be allocated when the error will be reported Oom

Freed 7k: Indicates that the GC has freed up 7K of memory

18% Free 11153k/13511k: Represents the heap memory used by Java (objects exist here), 18% free represents the current remaining 18% of heap memory (heap memories), 11153K represents the currently used heap memory, 13511K represents the total heap memory size (some articles on the Web this part is mistaken, many of the reproduced are the same one)

External 1632k/1672k:1632k says external memory is used, a total of 1672K external memory (note: This may only exist before Android 3.0)

Paused 89ms: In fact, there are two parts, one is the time to pause before the GC is called, and the time to pause when the GC is basically completed.

For more information, refer to: Http://stackoverflow.com/questions/4550757/android-logs-gc-external-alloc-gc-for-malloc

(1) No use of Convertview

There is no processing, it is not recommended to write this. If the amount of data is small, but if the list item data is very large, the view will be recreated each time, set the resources, severely affect performance, so from the beginning do not use this way

@Override Public View GetView (int. position, View Convertview, ViewGroup parent) {//get A view that disp            Lays the data at the specified position in the data set.            Start timing, performance test with Nanotime will be more accurate, because it is nanosecond-level long startTime = System.nanotime ();            View item = minflater.inflate (R.layout.list_item, NULL);            ImageView img = (ImageView) Item.findviewbyid (r.id.img);            TextView title = (TextView) Item.findviewbyid (r.id.title);            TextView info = (TextView) Item.findviewbyid (r.id.info);            Img.setimageresource (R.drawable.ic_launcher);            Title.settext ("Loulijun");                        Info.settext ("Www.cnblogs.com/loulijun");            Stop timer Long endTime = System.nanotime ();                        Time-consuming long spendtime = (endtime-starttime);            Sumtime + = Spendtime;            LOG.D ("Googleio", "position at:" +position+ "--sumtime:" +string.valueof (Sumtime));        return item;} 

Test results:

Currently, VMS are allocated only 5767k+518k memory, while memory spikes are 32M

At first, and the heap memory only applied for 5767K, used memory 3353K, note the change in data size: Time: 167633055ns = 0.167633055 seconds

When pulled to 1000, the heap memory total has applied for 9607K, has been used in memory 7245K, obviously is larger than the beginning, time: 3435241667ns=3.435241667 seconds

When pulled to 2000, heap memory total 13511K, used memory 11153K, time: 6660369835ns = 6.660369835 seconds

---------------------------I created 10,000 more listview, test until memory leak, prove peak is 32M, without using convertview caused memory leak, when memory leaks, hand prompt force Close and write the error to/data/anr/traces.txt, you can adb pull down to view specific information

(2) test data after using Convertview (after optimization)

By caching Convertview,convertview, you can cache Convertview in the viewable range, and when you swipe down again to start updating view, this way you can use the cache Convertview to determine if a view is not present in the cache , if there is already a view in the cache that can be leveraged, this will reduce the creation of many view and improve performance

@Override Public View GetView (int. position, View Convertview, ViewGroup parent) {//get A view that disp            Lays the data at the specified position in the data set.            if (Convertview = = null) {Convertview = minflater.inflate (R.layout.list_item, NULL);                        }//Start timing, performance test with Nanotime will be more accurate, because it is nanosecond-level long startTime = System.nanotime ();            ImageView img = (ImageView) Convertview.findviewbyid (r.id.img);            TextView title = (TextView) Convertview.findviewbyid (r.id.title);            TextView info = (TextView) Convertview.findviewbyid (r.id.info);            Img.setimageresource (R.drawable.ic_launcher);            Title.settext ("Loulijun");                        Info.settext ("Www.cnblogs.com/loulijun");            Stop timer Long endTime = System.nanotime ();                        Time-consuming long spendtime = (endtime-starttime);            Sumtime + = Spendtime; LOG.D ("GooglEIO "," position at: "+position+"--sumtime: "+string.valueof (Sumtime));        return convertview; }

Test data I still use 2000, 10000 is too big (10,000 years too long, seize)

Test results:

This time has been pulled to the end is significantly smoother than just now, and the GC freed memory is significantly less, the last time and the current use of memory is much smaller, after optimization is indeed much better

When the position is 1000, there is no way to call the GC, time: 213653551ns=0.213653551 seconds, the amount, the gap is a bit large, the above reached 1000 when the time to reach 3.43 seconds.

When the position is 2000, has used only 3068K memory, heap total memory 6215K, and external memories is 0K, time: 378326396ns = 0.378326396 seconds, the performance gap is so big, are a bit unbelievable. Also do not know this way is right, if there is inappropriate place, but also hope that Daniel can give the correct answer

(3) using contentview+ static Class Viewholder class

Implemented by Convertview+viewholder, Viewholder is a static class, and the key benefit of using Viewholder is to cache the view that displays the data, which speeds up the responsiveness of the UI.

When we judge Convertview = = NULL, if it is empty, it will be assigned to Convertview according to the item layout (XML) of the list that was designed. and generate a viewholder to bind the individual view controls inside the Converview (those controls inside the XML layout). Then use the Convertview Settag to set the Viewholder to tag so that the system draws the ListView from the tag the second time it is drawn. (See the code below)

If Convertview is not empty, it will use Convertview's Gettag () to obtain a viewholder.

Static Class Viewholder

Define static classes Viewholder static class    Viewholder    {public        ImageView img;        public TextView title;        public TextView info;    }
@Override Public View GetView (int. position, View Convertview, ViewGroup parent) {//get A view that disp                        Lays the data at the specified position in the data set.            Start timing, performance test with Nanotime will be more accurate, because it is nanosecond-level long startTime = System.nanotime ();                        Viewholder Holder;                if (Convertview = = null) {holder = new Viewholder ();                Convertview = minflater.inflate (R.layout.list_item, NULL);                Holder.img = (ImageView) Convertview.findviewbyid (r.id.img);                Holder.title = (TextView) Convertview.findviewbyid (r.id.title);                Holder.info = (TextView) Convertview.findviewbyid (r.id.info);            Convertview.settag (holder);                }else {holder = (Viewholder) convertview.gettag ();                Holder.img.setImageResource (R.drawable.ic_launcher);                Holder.title.setText ("Loulijun"); Holder.info.setText("Www.cnblogs.com/loulijun");            }//Stop timing long endTime = System.nanotime ();                        Time-consuming long spendtime = (endtime-starttime);            Sumtime + = Spendtime;            LOG.D ("Googleio", "position at:" +position+ "--sumtime:" +string.valueof (Sumtime));        return convertview; }

Here, someone might ask Viewholder static class binding cache Convertview and direct use of Convertview what is the difference, whether duplicate

Here, the authorities gave an explanation.

Two ways to lift adapter

To work efficiently the adapter implemented here uses the techniques:
-it reuses the Convertview passed to GetView () to avoid inflating View when It's not necessary

(Translate: Reuse cache Convertview pass to GetView () method to avoid populating unnecessary views)
-it uses the Viewholder pattern to avoid calling Findviewbyid () when It's not necessary

(Translate: Use Viewholder mode to avoid unnecessary calls to Findviewbyid (): Because too many Findviewbyid also affect performance)
The role of the Viewholder class
-the Viewholder pattern consists in storing a data structure in the tag of the view
Returned by GetView (). This data structures contains references to the views we want to bind data to,
Thus avoiding calling to Findviewbyid () every time GetView () is invoked

Viewholder mode stores a data structure in the label (tag) of the view returned by the GetView () method, which contains a pointer to our

A reference to the view to bind the data to avoid calling Findviewbyid () at each call to GetView ())

Test data: (Not much difference with direct use of convertview data)

When the position is 1000, the time: 199188216ns = 0.199188216 seconds, heap memory is no more than the use of Convertview ideal

When the position is 2000, the time: 336669887ns = 0.336669887 seconds, a little bit better than the direct use of Convertview, but the performance is similar

Memory leaks--contentview cache usage with listview optimization

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.