53

I'm trying to work out why my app is using so much memory. I often see it using between 15 and 18MB, which is substantially higher than I'd expect. I took a look at the heap size via DDMS and saw this:

enter image description here

That looked a tad suspicous because my app doesn't deal with large images at all. In fact the total sum of the drawables in my app is about 250KB. So I created a heap dump and used MAT to locate where all this memory was going. byte[] arrays were by far the greatest consumer, so I drilled down and noticed the following:

enter image description here

I have absolutely no idea why sPreloadedDrawables is responsible for such a high retained heap size. I also have no idea of how to identify the root cause, or how to 'fix' it.

Where should I go from here? My app works mostly in the background via services which don't deal with image data at all. I do have Activities that the user may choose to use, but again, they use small drawables which don't explain such a large heap size. I also checked for any nasty occurrences of Activity leaks etc, but didn't locate any.

EDIT: I noticed that the heap size is substantially lower when run in the emulator. This is quite confusing. :/

Cœur
  • 37,241
  • 25
  • 195
  • 267
Glitch
  • 2,785
  • 1
  • 27
  • 50
  • 1
    What Android version is you phone running?. I noticed that ICS preloads the image drawables, I guess to try a have a smoother UI experience and take advantage of the increased VM memory limit. So if your phone is on ICS and your emulator on 2.X that would explain the difference. I personally haven't tested the emulator running 4.X to check if the inflated memory is present too (I guess something for me to do later on). It's definitely there on my phone running 4.0.3. – sciutand Mar 25 '12 at 07:54
  • My phone is running stock Android 4.0.3, as is the emulator. – Glitch Mar 26 '12 at 14:02
  • What screen density/size are you using on emulator vs. device? – cistearns Apr 04 '12 at 15:57
  • Why worried about heap size when your app running in foreground? except when your app running as service – Superbiji Apr 04 '12 at 16:30

1 Answers1

44

The system will preload the default system resources, this is independent of your app resources, things like standard Drawables for check boxes and radio buttons. 10.5MB does seem large but there are a lot of default system resources and the Images are bigger once stored in memory. Preloading is not new, but the size of preload could be larger in ICS. Display density probably plays a part in this along with simply the addition of more system Drawables preloaded in ICS.

There is currently no way to reduce the memory held by the sPreloadedDrawables

It is unfortunate that there isn't a way to clear this after the app process is spawned for apps (especially games) that don't use most of the system Drawables. In this case though the large size of the preload resources seems to have been a bug with a specific release (or handset port) of ICS. It is otherwise normally a small amount of memory, so I doubt it would ever be necessary to have such a mechanism to reduce the preload memory use.

If you are running out of memory as a result of this cache then I'd probably file a bug report to Google.

You can trace through the resource preload process here if you are interested in more internal details. ZygoteInit.preloadResources

cistearns
  • 2,488
  • 21
  • 24
  • 4
    Yep. There will not be a feature to turn this off -- it is done in the zygote process, which is created once, and which all app processes spawn from. The resources it loads are thus shared across all processes. – hackbod Apr 05 '12 at 06:51
  • Thanks cistearns. My main issue is that I have users seeing this memory usage, and reporting it. It's affecting my star rating. My phone uses the same display as the iPhone 4, so it's very high density (something like 320dpi). On stock ICS it'd use upward of 20MB as reported by Android. Interestingly, after updating to a later build, this has dropped to about 7MB. So I'm wondering, could this also be a product of a bad stock ICS port? – Glitch Apr 05 '12 at 12:44
  • 1
    Sounds like it was was a bug that was causing more (or larger) items to be loaded during preload than intended. @hackbod I hadn't full dug into zygote to see that it was used as spawner (very cool), so I see why the preload always needs to happen. It would be possible to add support to clear the preload resources after the fork. But given that the the large size seems to have been a bug and it is normally small I doubt it would ever be necessary. – cistearns Apr 06 '12 at 22:20
  • 1
    @hackbod On Android 4.1, in a heap dump of our app, sPreloadedDrawables still accounts for about 5MB of retained memory. Is that considered the normal amount? I should also add, 2 of these resources that are in memory due to strong references from sPreloadedDrawables are 1MB in size *each*. Which default drawable in Android would take that kind of space? – mxk Feb 28 '13 at 16:35
  • 1
    It is really going to be device specific. Between new high resolution screens and OEMs adding custom default drawables it is possible for larger images to sneak in. – cistearns Mar 01 '13 at 06:51
  • lol it's funny to suggest Google will actually care about a bug report.. there's still bugs from 4-5 years ago that haven't been fixed, eh @hackbod? – StackOverflowed Jan 20 '15 at 22:53
  • Well it is really a handset specific bug, usually the preload set is not very big. While my suggestion to allow release of unused preloaded memory is valid, it only applies to subset of apps. Also in theory if copy-on-write is working correctly this preloaded memory could simply be shared, but that assumes they could ensure that it had its own page. This breaks down if the forked app ever writes to the same memory page that the preloaded assets are in. The fact that the preloaded assets (and any other stuff from Zygote) may be in a shared page is something MAT can't really take into account. – cistearns Jan 30 '15 at 07:14