Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lots of GC when scrolling ListView (with holder pattern)

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?

like image 518
Michał Klimczak Avatar asked Aug 20 '12 16:08

Michał Klimczak


2 Answers

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

like image 190
Robin Gawenda Avatar answered Nov 13 '22 01:11

Robin Gawenda


Make sure you have a background and/or a windowBackground for whatever is behind the ListView, I have seen this cause issues like this before.

like image 45
HandlerExploit Avatar answered Nov 13 '22 01:11

HandlerExploit