Lots of GC when scrolling ListView (with holder pattern)

android, android-listview, garbage-collection

Solution

android:scrollingCache="false"

Is the solution.

The docs say:

When set to true, the list uses a drawing cache during scrolling. This makes the rendering faster but uses more memory.

Now this does not give us any hint about the implementation details. I have an idea without investing hours of code analyzes. For caching purposes, like Google recommends in their own documents, they use WeakReferences or WeakHashMaps. But it looks like the Dalvik VM is a bit too eager to kill off these References and causes them to be rebuild every time. This explains the huge GC activity and the sluggish user experience.

Links: Blog about useless WeakReferences due to bug: http://chriswstewart.com/post/14199645893/improving-the-android-listview Dalvik VM bug discussion: https://groups.google.com/forum/#!topic/android-developers/66uw2t84rME

Problem

It's a similar question to this, but the solution doesn't work. The problem is that the scrolling of `ListView` is very sluggish which is because of lots and lots of GCs. I use holder pattern (view caching) as you can see in the code below: ``` public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.eventrow, parent, false); holder = new ViewHolder(); holder.title = (TextView) convertView.findViewById(R.id.eventTitle); holder.place = (TextView) convertView.findViewById(R.id.eventPlace); convertView.setTag(holder); } else { // Get the ViewHolder back to get fast access to the TextView // and the ImageView. holder = (ViewHolder) convertView.getTag(); } // Bind the data efficiently with the holder. holder.title.setText(((EventItem) getItem(position)).getTitle()); holder.place.setText(((EventItem) getItem(position)).getPlace_name()); return convertView; } ``` I removed `cacheColorHint` and custom selectors from my listview and from rows: ``` <ListView android:id="@+id/android:list" android:layout_width="fill_parent" android:layout_height="fill_parent" /> ``` This is how the log looks like: ``` 08-20 19:36:24.286: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed 364K, 46% free 3944K/7239K, external 1196K/1445K, paused 54ms 08-20 19:36:24.356: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed 228K, 49% free 3716K/7239K, external 1721K/1970K, paused 52ms 08-20 19:36:24.456: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed 5K, 49% free 3726K/7239K, external 2214K/2463K, paused 50ms 08-20 19:36:24.546: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed 2K, 49% free 3726K/7239K, external 2214K/2463K, paused 43ms 08-20 19:36:24.636: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed 2K, 49% free 3726K/7239K, external 2214K/2463K, paused 44ms 08-20 19:36:24.696: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 50ms 08-20 19:36:24.766: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 46ms 08-20 19:36:24.846: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 46ms 08-20 19:36:24.906: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 46ms 08-20 19:36:24.986: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 46ms 08-20 19:36:25.056: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 47ms 08-20 19:36:25.136: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 46ms 08-20 19:36:25.196: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 46ms 08-20 19:36:25.296: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 48ms 08-20 19:36:25.356: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3726K/7239K, external 2214K/2463K, paused 43ms 08-20 19:36:34.596: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed 7K, 49% free 3740K/7239K, external 2214K/2463K, paused 51ms 08-20 19:36:34.656: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed 1K, 49% free 3739K/7239K, external 2214K/2463K, paused 50ms 08-20 19:36:34.746: D/dalvikvm(12036): GC_EXTERNAL_ALLOC freed <1K, 49% free 3739K/7239K, external 2214K/2463K, paused 50ms ``` EDIT: It seems that the problem appears (almost) only when the `ListFragment` is first inflated. For the first scroll down and then up. After that the GCs are not so often. But sometimes the GCs appear everytime I scroll. I can see no regularity here. PLUS I can see the problem on HTC Desire (2.3.7 MIUI) but not on Sasmung Galaxy ACE (2.1). It only gets more confusing... Not so satisfying solution: When I use ``` android:scrollingCache="false" android:animationCache="false" ``` in my listview it seems ok. But the docs say it should be exactly otherwise if I understand well, so I'm a little bit confused. Where do I make mistake? What to do to have a smooth scrolling listview? Or would disabling `scrollingCache` have some negative effect which I can't see now?

Original source

Related problems