trying to avoid Grow heap (frag case) - android

I have a ViewPager with pageOffscreenPageLimit set to 1 (3 pages in total). I use it to display 4 bitmaps for each page. Bitmaps are loaded asynchronously, scaled down and all that stuff to avoid OutOfMemory exceptions. I noticed some 'stalls' scrolling the pages due to GC, here some piece of log:
03-22 13:05:06.320: V/test(11448): onPageSelected(2)
03-22 13:05:06.840: V/test(11448): destroyItem(0)
03-22 13:05:06.850: V/test(11448): instantiateItem(3)
03-22 13:05:06.900: D/dalvikvm(11448): GC_FOR_ALLOC freed 4578K, 29% free 15567K/21703K, paused 24ms
03-22 13:05:06.900: I/dalvikvm-heap(11448): Grow heap (frag case) to 18.265MB for 3128360-byte allocation
03-22 13:05:06.930: D/dalvikvm(11448): GC_FOR_ALLOC freed <1K, 15% free 18622K/21703K, paused 27ms
03-22 13:05:06.990: D/dalvikvm(11448): GC_CONCURRENT freed 49K, 15% free 18636K/21703K, paused 1ms+4ms
03-22 13:05:07.060: D/dalvikvm(11448): GC_FOR_ALLOC freed 3221K, 25% free 16298K/21703K, paused 21ms
03-22 13:05:07.060: I/dalvikvm-heap(11448): Grow heap (frag case) to 18.979MB for 3128360-byte allocation
03-22 13:05:07.100: D/dalvikvm(11448): GC_CONCURRENT freed <1K, 11% free 19353K/21703K, paused 1ms+3ms
03-22 13:05:07.170: D/dalvikvm(11448): GC_FOR_ALLOC freed 3130K, 22% free 17026K/21703K, paused 20ms
03-22 13:05:07.170: I/dalvikvm-heap(11448): Grow heap (frag case) to 19.694MB for 3131424-byte allocation
03-22 13:05:07.210: D/dalvikvm(11448): GC_CONCURRENT freed <1K, 8% free 20084K/21703K, paused 1ms+3ms
03-22 13:05:07.240: V/test(11448): onPageSelected(3)
03-22 13:05:07.270: D/dalvikvm(11448): GC_FOR_ALLOC freed 42K, 8% free 20053K/21703K, paused 22ms
03-22 13:05:07.270: I/dalvikvm-heap(11448): Grow heap (frag case) to 20.359MB for 729656-byte allocation
03-22 13:05:07.290: D/dalvikvm(11448): GC_FOR_ALLOC freed <1K, 8% free 20765K/22471K, paused 20ms
03-22 13:05:07.320: D/dalvikvm(11448): GC_FOR_ALLOC freed 3094K, 22% free 17739K/22471K, paused 19ms
03-22 13:05:07.330: I/dalvikvm-heap(11448): Grow heap (frag case) to 20.386MB for 3128360-byte allocation
03-22 13:05:07.350: D/dalvikvm(11448): GC_FOR_ALLOC freed <1K, 8% free 20793K/22471K, paused 20ms
03-22 13:05:07.390: D/dalvikvm(11448): GC_CONCURRENT freed 2K, 8% free 20799K/22471K, paused 1ms+3ms
03-22 13:05:07.490: D/dalvikvm(11448): GC_FOR_ALLOC freed 38K, 8% free 20772K/22471K, paused 27ms
03-22 13:05:07.490: I/dalvikvm-heap(11448): Grow heap (frag case) to 21.061MB for 729656-byte allocation
03-22 13:05:07.520: D/dalvikvm(11448): GC_FOR_ALLOC freed <1K, 8% free 21484K/23239K, paused 21ms
03-22 13:05:07.760: V/test(11448): destroyItem(1)
03-22 13:05:07.760: V/test(11448): instantiateItem(4)
03-22 13:05:07.820: D/dalvikvm(11448): GC_FOR_ALLOC freed 6063K, 34% free 15558K/23239K, paused 24ms
03-22 13:05:07.820: I/dalvikvm-heap(11448): Grow heap (frag case) to 18.526MB for 3411216-byte allocation
03-22 13:05:07.850: D/dalvikvm(11448): GC_FOR_ALLOC freed 19K, 19% free 18869K/23239K, paused 19ms
03-22 13:05:07.900: D/dalvikvm(11448): GC_CONCURRENT freed 6K, 19% free 18908K/23239K, paused 1ms+4ms
03-22 13:05:07.960: D/dalvikvm(11448): GC_FOR_ALLOC freed 3463K, 30% free 16334K/23239K, paused 20ms
03-22 13:05:07.960: I/dalvikvm-heap(11448): Grow heap (frag case) to 19.284MB for 3411216-byte allocation
03-22 13:05:07.980: D/dalvikvm(11448): GC_FOR_ALLOC freed 0K, 16% free 19665K/23239K, paused 21ms
03-22 13:05:08.030: D/dalvikvm(11448): GC_CONCURRENT freed 5K, 16% free 19674K/23239K, paused 1ms+3ms
03-22 13:05:08.100: D/dalvikvm(11448): GC_FOR_ALLOC freed 3433K, 27% free 17033K/23239K, paused 22ms
03-22 13:05:08.100: I/dalvikvm-heap(11448): Grow heap (frag case) to 19.966MB for 3411216-byte allocation
03-22 13:05:08.140: D/dalvikvm(11448): GC_CONCURRENT freed <1K, 13% free 20363K/23239K, paused 2ms+3ms
03-22 13:05:08.220: D/dalvikvm(11448): GC_FOR_ALLOC freed 3407K, 24% free 17749K/23239K, paused 19ms
03-22 13:05:08.220: I/dalvikvm-heap(11448): Grow heap (frag case) to 20.666MB for 3411216-byte allocation
03-22 13:05:08.260: D/dalvikvm(11448): GC_CONCURRENT freed 1K, 10% free 21079K/23239K, paused 1ms+4ms
the Heap Size remains at 24Mb and don't grow. Also, in the destroyItem I try to free the ImageView, setting the drawables and callbacks to null. Can I improve the performance or this is a normal behaviour?

I guess you have two options considering you are using Viewpager and Imageviews
About image views try to use powerful image downloading and caching library for Android like Picasso,latest Volley Imageloading(really helpful for large size images) to improve the image loading capabilities in a efficient way.
About Viewpager you have to use efficient adapter FragmentStatePagerAdapter:
This version of the pager is more useful when there are a large number of pages, working more like a list view. When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.
please think before you are using FragmentPagerAdapter becouse it stores the whole fragment in memory, and could increase a memory overhead if a large amount of fragments are used in ViewPager. In contrary its sibling, FragmentStatePagerAdapter only stores the savedInstanceState of fragments, and destroys all the fragments when they lose focus. Therefore FragmentStatePagerAdapter should be used when we have to use dynamic fragments, like fragments with widgets, as their data could be stored in the savedInstanceState. Also it wont affect the performance even if there are large number of fragments. In contrary its sibling FragmentPagerAdapter should be used when we need to store the whole fragment in memory. When I say the whole fragment is kept in memory it means, its instances wont be destroyed and would create a memory overhead. Therefore it is advised to use FragmentPagerAdapter only when there are low number of fragments for ViewPager. It would be even better if the fragments are static, since they would not be having large amount of objects whose instances would be stored. Hope this clears out the difference between Android FragmentPagerAdapter and FragmentStatePagerAdapter.
Try to learn Google android gallary app example, use image view loading animations to make a great user experience.
I hope this will solves your grow heap problems.
Credits:FragmentPagerAdapter vs FragmentStatePagerAdapter

Related

do I need to take care of memory management when using Picasso?

I'm using Picasso to load tons of (relatively small) images inside a BaseAdapter combined with my own implementation of an endless ListView. Basically I'm using almost the simplest setup possible:
Picasso.with(c)
.load(friend.getPhoto_url_200())
.resize(200, 200)
.centerCrop()
.placeholder(R.drawable.default_profile)
.error(R.drawable.default_profile)
.transform(transformation)
.into(holder.imgAva);
AFAIK, Picasso takes care of image caching and recycling on its own. Looking at the logs I see that the amount of memory being freed by GC continuously increases when loading more items (though the amount of RAM used by the application only increases by <3MB when comparing 10 vs 500 loaded items):
D/dalvikvm﹕ GC_FOR_ALLOC freed 481K, 8% free 23093K/24944K, paused 14ms, total 14ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 348K, 7% free 23399K/25104K, paused 12ms, total 12ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 798K, 8% free 23587K/25532K, paused 14ms, total 14ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 415K, 7% free 24053K/25852K, paused 13ms, total 13ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1761K, 9% free 24153K/26428K, paused 21ms, total 21ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 664K, 9% free 24297K/26428K, paused 18ms, total 18ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 354K, 7% free 25064K/26860K, paused 18ms, total 19ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1064K, 9% free 25568K/27840K, paused 19ms, total 19ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1581K, 10% free 25732K/28480K, paused 22ms, total 26ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1202K, 9% free 26343K/28780K, paused 20ms, total 20ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1514K, 10% free 26537K/29448K, paused 20ms, total 20ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1265K, 10% free 26849K/29768K, paused 14ms, total 14ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1243K, 10% free 27381K/30172K, paused 19ms, total 20ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1615K, 10% free 27956K/30972K, paused 23ms, total 23ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1595K, 10% free 28555K/31588K, paused 21ms, total 21ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 2071K, 11% free 29106K/32532K, paused 16ms, total 16ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 1879K, 10% free 29837K/33052K, paused 22ms, total 22ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 2012K, 11% free 30596K/34132K, paused 21ms, total 21ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 2570K, 11% free 31431K/35204K, paused 20ms, total 20ms
D/dalvikvm﹕ GC_FOR_ALLOC freed 3169K, 12% free 32091K/36276K, paused 22ms, total 22ms
At some point I'm also getting a JIT message telling me it's resizing the JIT table to allocate more memory.
In this regard, my questions are:
Can I do anything to further optimize the process or should I leave Picasso handle it on its own?
I did not have the opportunity to test this on a low-end device, the Nexus 5 is a relatively powerful device so I wasn't able to reach the heap limit. How would Picasso behave when it starts running out of memory? Will it delete cached items/decrease the amount of images set into the list ImageViews/do something else or will it just throw an OutOfMemoryError?
are there any general tips that should be considered when using Picasso to load images into a ListView?
Using picasso is a very good choice it handles Disk and memory caching with various expiration policies Images downsampling to the target view size to improve performance and reduce memory usage Batching UI updates to improve UI responsiveness So you normally don't have to worry about memory, but i suggestyou give a shot to the volley lib it's far more better

GC run too often

This is a general question.
In my application the garbage collector is running too often (several times per second) and doesn't free a lot of memory (less than 1Mb).
The thing is, the heap size doesn't grow anymore. It takes about 40Mb, sometimes 60Mb on other phones where the maximum for an application is 128Mb (Galaxy S4) or 196Mb (Nexus 4).
Why does the GC run so often ?
Below is a part of the logcat when the GC runs too often. The application is freezing. I don't even do anything, I just try to zoom a map.
06-07 16:50:52.003: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60015K/72980K, paused 51ms, total 51ms
06-07 16:50:52.053: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60016K/72980K, paused 51ms, total 51ms
06-07 16:50:52.113: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60016K/72980K, paused 52ms, total 52ms
06-07 16:50:52.163: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60017K/72980K, paused 52ms, total 52ms
06-07 16:50:52.213: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60017K/72980K, paused 51ms, total 52ms
06-07 16:50:52.273: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60018K/72980K, paused 51ms, total 51ms
06-07 16:50:52.324: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60018K/72980K, paused 51ms, total 51ms
06-07 16:50:52.374: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60019K/72980K, paused 52ms, total 52ms
06-07 16:50:52.434: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60019K/72980K, paused 53ms, total 53ms
06-07 16:50:52.484: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60020K/72980K, paused 52ms, total 52ms
06-07 16:50:52.544: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60020K/72980K, paused 56ms, total 56ms
06-07 16:50:52.594: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60021K/72980K, paused 52ms, total 52ms
06-07 16:50:52.654: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60021K/72980K, paused 52ms, total 52ms
06-07 16:50:52.704: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60022K/72980K, paused 52ms, total 52ms
06-07 16:50:52.754: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60022K/72980K, paused 52ms, total 52ms
06-07 16:50:52.814: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60023K/72980K, paused 52ms, total 52ms
06-07 16:50:52.864: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 6023K/72980K, paused 51ms, total 51ms
06-07 16:50:52.924: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60024K/72980K, paused 55ms, total 56ms
06-07 16:50:52.974: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60024K/72980K, paused 52ms, total 52ms
06-07 16:50:53.024: D/dalvikvm(26176): GC_FOR_ALLOC freed 256K, 18% free 60025K/72980K, paused 52ms, total 52ms
Your problem is related to how Google Maps Android API works and how much memory is allocated by your application.
40-60 MB might problematic because it takes longer to execute single GCollection. As a side note: I noticed adding 1000 markers takes significantly longer when having 15 MB allocated comapred to when having 5 MB.
In addition to that every call to the Google Play Services APIs is doing IPC, which in turn forces GC according to this answer. It is possible that such IPC calls are done when panning or zooming.
It would be preferable to keep your memory footprint much lower.
The GC runs when it needs to. In general, (even on the DVM) it really does know, way better than you do, when it needs to run. If you frame this problem not as a problem with the GC, but as a problem with your app's memory, it might help you find a solution.
The most likely reason for frequent GCs is that you are nearly out of memory. This could happen, for instance, if you allocate lots of short-lived objects: You allocate them fast, but forget them just as quickly. Every time the GC runs, it successfully recovers enough memory for the app to continue... but just as quickly, you fill memory again.
If this is actually what is happening, then, if you had more memory, as suggested by #parry, you would just delay the problem. GCs would occur less frequently, but take longer to run (because they would collect more garbage). That might be sufficient, but probably not.
Check to see if you are allocating objects in a routine that is called frequently (for instance, your draw routines).
If you believe the GC is acting stupid (quite possible), and that the VM has more memory to spare, then you could try forcing it to increase the heap size by asking for a one off 1/5/10 MB allocation (guarding it with a try-catch for OOME).
This might cause the GC to clean up more on each cycle, or increase the chances for a full GC to occur.
Another heuristic, which works on a PC, is calling System.GC() x times in a loop to trigger a full GC.
All in all, I came across it myself and it sucks.

Why is Android allocating twice as much memory as I expect for an image?

I'm loading an image resource in an Android application using setImageResource(), and for some reason this is using a lot of extra memory.
This is what I see when the image is loaded:
03-29 15:16:56.687: D/dalvikvm(23616): GC_FOR_ALLOC freed 42K, 11% free 16175K/18119K, paused 11ms
I/dalvikvm-heap(23616): Grow heap (frag case) to 23.154MB for 7675216-byte allocation
D/dalvikvm(23616): GC_CONCURRENT freed 3K, 8% free 23667K/25671K, paused 1ms+2ms
D/dalvikvm(23616): GC_FOR_ALLOC freed 0K, 8% free 23667K/25671K, paused 10ms
I/dalvikvm-heap(23616): Grow heap (frag case) to 39.624MB for 17272816-byte allocation
D/dalvikvm(23616): GC_CONCURRENT freed 0K, 5% free 40535K/42567K, paused 1ms+2ms
The jpg is 1599x1200, so I would expect the first allocation - 1599 * 1200 * 4 = 7675200.
What's going on with the 17MB allocation?
It is most likely you put your image into drawable-mdpi or just drawable directory, but run the app on the hdpi device. In this case image's dimensions will be scaled by 1.5.
1599 * 1200 * 4 * 1.5 * 1.5 = 17269200b ~ 17mb
You should probably move the image to drawable-nodpi directory to avoid unwanted scale.

Android app using large portions of the heap, no success identifying memory leaks

I've got a relatively light weight app that seems to be using large portions of heap memory (in my opinion) and it doesn't shrink after garbage collection.
I haven't been able to identify any memory leaks by using the Eclipse Memory Analyzer. My knowledge of this tool is though very limited.
Snippet from LogCat:
(Note that this is only a small snippet from a log dump. The LogCat seems to output garbage collection messages almost no matter what I do inside my app, continously. The amount of free heap remains relatively stable though, indicating (to me) that there is no actual memory leak?)
01-22 17:04:51.672: D/dalvikvm(16274): GC_CONCURRENT freed 721K, 10% free 8074K/8968K, paused 4ms+7ms, total 33ms
01-22 17:04:53.742: D/dalvikvm(16274): GC_CONCURRENT freed 523K, 12% free 7977K/8968K, paused 4ms+5ms, total 29ms
01-22 17:04:54.012: D/dalvikvm(16274): GC_CONCURRENT freed 457K, 12% free 7941K/8968K, paused 3ms+2ms, total 29ms
01-22 17:04:56.432: D/dalvikvm(16274): GC_CONCURRENT freed 237K, 10% free 8116K/8968K, paused 2ms+2ms, total 22ms
01-22 17:04:58.632: D/dalvikvm(16274): GC_CONCURRENT freed 445K, 10% free 8094K/8968K, paused 3ms+3ms, total 33ms
01-22 17:05:00.332: D/dalvikvm(16274): GC_CONCURRENT freed 499K, 11% free 8013K/8968K, paused 1ms+10ms, total 33ms
01-22 17:05:00.582: D/dalvikvm(16274): GC_CONCURRENT freed 487K, 12% free 7916K/8968K, paused 3ms+6ms, total 38ms
01-22 17:05:02.382: D/dalvikvm(16274): GC_CONCURRENT freed 223K, 10% free 8107K/8968K, paused 3ms+3ms, total 23ms
01-22 17:05:03.882: D/dalvikvm(16274): GC_CONCURRENT freed 436K, 10% free 8107K/8968K, paused 9ms+12ms, total 76ms
01-22 17:05:05.392: D/dalvikvm(16274): GC_CONCURRENT freed 528K, 11% free 8059K/8968K, paused 2ms+3ms, total 35ms
01-22 17:05:06.962: D/dalvikvm(16274): GC_CONCURRENT freed 489K, 11% free 7998K/8968K, paused 4ms+3ms, total 32ms
01-22 17:05:07.212: D/dalvikvm(16274): GC_CONCURRENT freed 487K, 12% free 7928K/8968K, paused 3ms+3ms, total 29ms
01-22 17:05:08.832: D/dalvikvm(16274): GC_CONCURRENT freed 226K, 10% free 8094K/8968K, paused 3ms+3ms, total 22ms
01-22 17:05:12.152: D/dalvikvm(16274): GC_CONCURRENT freed 453K, 10% free 8080K/8968K, paused 4ms+3ms, total 48ms
The above is a result of "heavy use", involving spamming on buttons and changing orientation several times. My concern is the fact that only ~10% of the heap seems to be free/left for further expansions.
For your information, the XML file representing the current fragment's layout (at the time of the above output) is a ScrollView with a TableLayout inside, consisting of about 25 TableRow elements, perhaps this is the cause for such large hogging of heap memory?
Is this something to worry about at all?
Please let me know if you prefer to look at some of my code. Thanks in advance.
Update:
The app is basically just one Activity containing two fragments. One of said fragments get swapped out with other fragments based on user interaction.
Think of it as a typical Menu-Content app (like the default Android Contacts app). MenuFragment (Contacts list) on the left and some ContentFragment (Contacts details) on the right. So far there is not too much functionality
involved except for setting up the UI behavior. There is nothing happening in the background, no saving of states or similar. I've basically focused on making sure that
the correct fragment shows up when I select an item from my MenuFragment, that the correct layouts are drawn when a fragment launches, and that the correct fragment
is displayed when the user presses the back button.
The heap will adjust it's size automatically based upon the needs of your app. Small heaps are faster on the GC so Android will not start you out with a 64 MB heap if you don't need it. While you're app is using a lot of your current heap, the heap is extremely small for an Android 4.x app. A bare bones 4.x app alone will use up 7Mb. From what I see, you're fine.

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?
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
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.
try
listView.setCacheColorHint(0);
&
protected void onDestroy() {
System.gc();
super.onDestroy();
}

Categories

Resources