I'm having severe memory issues in my application [1]. In order to investigate this, I took heapdumps of my app at different states. I saw that some bitmaps were taking huge amounts of memory. I wrote a small tool [2] that decodes the byte arrays to Windows bitmap files (.bmp), so that I can see the bitmaps and compare them to the files I have in my res/drawable folder.
What I discovered is that all my files are upsampled twice.
I first checked with the biggest one had: a byte array buffer of more than 9MB in the heap, which was decoded to be a nice 1920x1280 picture, while the original one was a 960x640 png file.
I tried with the second biggest, over 3MB, which once decoded showed a nice 754x1200 picture, the original size was... guess what? A nice 377x600 jpg file.
What gives?
I have enabled HW acceleration in my Android Manifest file (though I'm not sure I really need it, I'm just using some basic views and activities).
I'm running stock Android 4.0.2 on a GSM Galaxy Nexus (yakju). I'm receiving feedback from my testers that the issue is present on their 4.0.3 Nexus S, though I couldn't check their heap dumps yet.
I'm trying to save memory here, if Android doubles everything, no wonder the app crashes quickly because the heap usage gets too high (around 64MB in my case). I hope there's a reason and a way around it.
References:
OutOfMemoryError when loading activities
How to actually see a Bitmap taken from an Android heap dump
When you put images in res/drawable, Android will assume they have a dpi of 160, i.e. it is the same as putting them in res/drawable-mdpi. Galaxy Nexus is an xhdpi device, i.e. it has a (generalized) dpi of 320. To compensate for the high resolution display, Android will upsample the images with 200%.
The solution is simple, just put the images in res/drawable-xhdpi instead. Then the declared dpi of the images will match the display you run on, and Android will not perform any scaling of the images.
Please refer to http://developer.android.com/guide/practices/screens_support.html for more info.
Related
Apologies in advance for such a basic question, but this is my first app and I can't quite find a clear answer for my situation. All the images in my app are stored in the drawable folder, I'm NOT downloading any images from the internet. All the information I come across when it comes to multiple image sizes seems to refer to the occasion when the app is fetching images from the internet.
So currently most the images in my app are one size, customized for the largest size - xxxhdpi. However, I understand the app is doing some work to "shrink down" those images for the xxhdpi size screens.
I'm having second thoughts about this one size fits all approach. I'm thinking that perhaps the app doing the work to shrink the image down might take up extra memory and negatively impact performance. I've been looking at the Android Studio Profiler and I've been trying to understand the Graphics Process when I look at the Memory Graph.
More generally speaking, is there a benefit to having the smallest size images possible, even for the xxxhdpi? For example, does it hurt (memory wise or in some other aspect) to use a .png image when I could use a lower quality jpg? Again, just to super clear, this is just in the scenario when the app has all of its images in the drawable folder. My app has options where players can change the game background and other images so I want to be sure I'm optimizing how the images for best performance. Thanks.
Memory. If you load a bitmap of x by y pixels, in memory that takes 4*x*y bytes. For a full screen image, you can expext that to be 4000*1000*4 or 16 MB. That's a good chunk of memory to a small device, which also tends to have less RAM. If instead it needed one at half the resolution, you would have 2000*500*4, or 4 MB.
Obviously this scales with size. The smaller your images, the less memory wasted. I wouldn't argue that you need to provide every size, but if you're using large images I'd provide more than one. Also, for anything that isn't incredibly complex (like icons) I'd consider vector images instead (although that's a CPU time vs memory tradeoff).
You mentioned png vs jpg. There's two things to consider there: apk size and image quality. JPG is smaller, so it will lead to a smaller apk size. PNG is lossless, so it will have higher quality (although whether that matters requires a human visual check- it matters less than you'd think on a lot of things). Interestingly it doesn't effect the amount of memory used at runtime, because both are held in the Bitmap object uncompressed.
I have a lot of "out of memory" reports in an application from Galaxy S4 users.
The app is working with Bitmap . It has a graphical UI. It works good on all devices but on S4 it crashes.
Do you know if we need any special memory management for S4?
I don’t believe that S4 introduces something out of the ordinary with Memory management or Images. I guess looking at the memory usage of the app will be helpful.. Follow this guide to look at possible leaks and memory consumption of your app.
http://developer.android.com/tools/debugging/debugging-memory.html
Since you said that you deal with images in your apps... In my apps I have had memory problems with bitmaps. A good tip is to use LRUCache to cache and manage bitmaps. Follow the link below to understand LruCache.
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Hope this helps!
In order to solve this, you need to understand how images use memory.
Imagine an image, 800x800 pixels. Without any scaling, this will require approximately 2.5MB of memory. Width x height x 4 bytes.
All loaded images are stored on the heap which is limited in size (there are many discussions on here about heap size).
Now load that image into an ImageView which is displayed on a 1024x768 screen, the size of the ImageView being 800x800 - the same size as the image. You are using DIP as recommended so that your UI scales.
Your 1024x768 display has 786,432 pixels. The S4 has 1920x1080 = 2,073,600 pixels. Approximately 2.6 times as many as the 1024x768 device.
If you do not do anything to scale that image and you do not use the density and resolution "bucket" resource folders, then that same image now needs 2.5x2.6MB = 6.6MB.
The key point is that unless you control it, your image will use
different amounts of heap memory (which is limited, it doesn't matter
how much RAM the device has) on different devices.
I suspect that your app would have problems on Nexus devices too.
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
http://developer.android.com/guide/practices/screens_support.html
Out of curiosity, I just recently tested my Android App for Memory Leaks, using the Eclipse Memory Analyzer.
I came across a strange Bitmap with the size of 512 x 512 pixels using up about 1 Megabyte of my devices heap memory.
I checked my drawables folder and could not find a bitmap of that size (512 x 512).
I started googling and came across this question, where a user explains how to get the actual Image behind a "memory leak" reference in the Memory Analyzer:
MAT (Eclipse Memory Analyzer) - how to view bitmaps from memory dump
I followed the tutorial and with the help of GIMP, I extracted the following Image:
So my questions are:
What is that?
What is it doing in my applications heap?
How do I get rid of it?
Does anyone else have the same bitmap in his heap?
Notes:
In my drawables folder is no Bitmap looking like that
The largest Bitmap my app uses is 140 x 140 pixels
I have a feeling that this Bitmap somehow comes from the system
The Bitmap is in heap right after app start - without any user interaction
I am debugging on a HTC One S, Android 4.1 Cyanogen Mod (Screen 540 x 960)
I am not using external Libraries
Update:
With the help of Selvin's suggestion and my personal felling that this could be a System-issue, I tested two other apps of mine.
Both of the apps I tested also showed the same Bitmap in the Memory Analyzer with exactly the same amount of bytes consumed:
Furthermore, I was able to find out that:
The source of the Bitmap is always associated with the LAUNCHER Activity of the app.
So what to do about that?
Is there a way to get rid of it?
Since I do memory-intensive operations in my app, I'd like to have as much heap available as possible.
The default window background used by Android is a 512x512 image (the blueish-dark gradient you see with the dark theme or the gray-white gradient with the light theme). On capable devices, this image is replaced with a procedural gradient as of Android 4.2.
Note that this bitmap is normally loaded in Zygote and shared by all the apps. It might show up in heap dumps if the dump doesn't exclude Zygote-allocated objects.
Here are the two 512x512 backgrounds I'm talking about if you're interested:
https://github.com/android/platform_frameworks_base/blob/jb-mr0-release/core/res/res/drawable-nodpi/background_holo_dark.png
https://github.com/android/platform_frameworks_base/blob/jb-mr0-release/core/res/res/drawable-nodpi/background_holo_light.png
I'm working with Android on eclipse and while testing the code, I seemed to notice the heap raising to 44MB. I'm searching for the variable that I'm keeping alive and I can't seem to find it for a few days. While looking in the heap (DDMS -> Heap) I get the following:
I tried clicking the "Dump HPROF file" as showed in here, but I don't get the save file dialog and I can't analysis it.
so I'm trying to override it untill I get a new computer..
I'm running Android eclipse on Windows 7.
EDIT:
The problem was the ImageViews I keep; I have two images that I set resource via the code with an image of 0.5MB. My question is: is it possible to add ImageViews without growing the heap by that much? and how come 2 images of 0.5MB cause 40MB grow heap?
To answer your edited-in question, your "0.5MB" images are probably compressed. Jpeg or PNG, most likely.
That doesn't matter once they get decoded. What matters then are the dimensions of the image and the bitmap format being used. A typical bitmap in Android is ARGB_8888, which is 32 bits(4 bytes) per pixel.
That means for every pixel(w*h), it costs 4 bytes of space. Looking at the max size(~15MB), It looks like your image is probably about 1600x1200, or around 2MP.
That's 1600 * 1200 * 4 = 15360000, or ~15MB for each image.
For most things, you shouldn't need an image that large on a mobile device. I don't know your application, but if you don't need it that large, you should look into Loading Large Bitmaps Efficiently.
I've recently started testing for my game on other peoples phones. For some reason the whole game is getting really "blurry" for their phones, but not for mine. All of them has got a higher android version then I do.
I've tried finding a good answer around the web for this, but all I can find is the answer for if you are using the res/drawable folders. I am loading my images from the assets folder with a special load method. I am then stretching them out when I draw them onto the screen with the "c.drawBitmap()". I am drawing using an "android.view.View".
So now, anyone that has the answer for turning the anti-aliasing off for bitmaps when creating 8-bit games. It would be an impossibility for me to resize the images before rendering them onto the screen, because of me creating an image from an integer array, that refreshes with a rate of about 60 fps.
That blurriness, is most probably because of low resolution of your bitmaps. It may be fine on the test device of yours, but when you use them on higher resolution screens you will either get raw/pixelated or blurry/AA'd results after scaling. An appropriate solution is to have different images for different resolutions, or to be more accurate; densities. Android already do the choosing part:
ldpi
mdpi
hdpi
...
I am assuming you know these identifiers.
Put your high resolution image to res/drawable-hdpi, low resolution to res/drawable-ldpi etc.