I'm loading 100 images from Asset folder to an array object. The pictures are quite small (png ~20k each), and im using this code do to it, and to prevent memory leak & optimized performances:
in a loop:
// create resized bitmap from asset resource
InputStream istr = assetManager.open(pics[i]);
Bitmap b = BitmapFactory.decodeStream(istr);
b = Bitmap.createScaledBitmap(b, 240, 240, true);
where pics[i] is a list of filenames which sits in my Asset folder.
The code works for me, but i still receive from time to time Errors from users (i see it on Developer Console errors):
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
Is there anything i can do to improve it? or this is Android's world, we can never deliever a perfect application?
Of course you can improve something: Don't load too much pictures into the memory at the same time (or reduce their size). Some devices don't have much memory available. Your device may have a higher heap limit than some of your customers phones. Therefore it crashes for them when it works for you (see this video for some heap limits [at 4:44]).
You may get the available heap size via ActivityManager.getMemoryClass().
To improve this, test which pictures you need right now (which are displayed) and are which not. Load only the required ones and recycle the bitmaps you don't need anymore.
Also try using the BitmapFactory.decodeResource() and BitmapFactory.Options.inSampleSize. This allows you to load images at a lower resolution directly without loading them at the full size and then resizing them as you did here.
Bitmaps aren't compressed so they are stored in width * height * 4 bytes. It means that every image uses about 225 KB of memory. 100 images require about 22 MB of memory. The minimal heap size is 16 MB, but devices usually have 24+ MB heap. And this heap is used not only for data but also for activities, view and so on. That means you can't load 100 bitmaps of this size.
As a rule of thumb you should only ever need to show what the user can actually see. Holding anything else (graphics) in memory is just icing on the cake. This is why devices with higher resolution screens will have larger heap sizes available.
For example, on a 320x480 screen, you would only need as a minimum, 320x480x4=614400 (600kb).
Taking this concept into mind, you need to consider whether you need to hold 100 Bitmaps in memory. Is the user looking at 100 Bitmaps at one time? In that case you can reduce the quality of the images without degrading the user experience (there are only so many pixels on the screen). Is the user scrolling through 100 Bitmaps? Then dump and load images dynamically as appropriate (with a bit of caching for smoothness).
There is always a workaround.
Related
I am using 10 png images of size 20-30kb in imageView, but the allocated memory increases from 70mb to 270mb when this activity loads.
So why this too much of memory is allocated to these images.
This is the screenshot of memory allocation
This is one of my image
File size doesn't matter. No, matter your image is of 20kb but its resolution is quite big. When image is loaded into memory it takes memory equal to totalNoOfDotsInImageBitmap * 4bytes
and totalNoOfDotsInImageBitmap = width *height of image.
4 bytes - because of ARBG ( 1 byte per argument) for single dot of bitmap
so reducing width and height of image may solve your problem.
Depending on where you are putting the assets it may be trying to load a file that is too large.
For instance, if you have it on drawable or nodpi-drawable a device with a low density will try to load a potentially large image.
Also, bear in mind that the actual file size is not that important as it is probably small due to compression, but the image has to be converted to bitmap when it gets drawn, so if the actual size is too much that can also cause an OOM.
If you have access to the original I would recommend using a vector drawable (it's a simple shape so should be ok) and AS will generate the required PNG files for older versions.
I'm looking at the Heap Dump, and I've taken out all initializing, in my Application's onCreate, as well as my Activity's. However, I'm still seeing a 1 mb byte[] allocation (likely a bitmap?) but I'm not requesting any. The biggest image I have in my drawable folders is 21 kb (156x156, so roughly 96kb as a Bitmap?). I just can't find where this Bitmap could be coming from. There are no themes being utilized. I am using ActionBarSherlock.
This is what MAT is showing for this allocation:
There's no way to stop system from preloading drawables. 1MB of sPreloadedDrawables is actually a small amount. More details here: Locating and remedying cause of large heap size
I have a frame animation with 135 frames that should swap 25 times per second. The frames are 700X1000 pixels with 240 dpi. The problem I have is that whenever I define in the XML animation file more than 5 frames the application crashes. The frames are found in the drawable folder. I tried copying them to the drawable-xhdpi but this did not solve the problem.
Thanks,
Simon
Problem that loading images consumes all heap memory (memory that has your application avaliable) which is 32MB or 64MB. Images are loaded in on heap as Bitmap in ARGB - 4 bytes per pixel. Try to subsample animation images. Your animation has 135*700*1000*4 bytes = 360.5 MB.
You can use method decodeResource with BitmapFactory.Options opts that has parameter inSampleSize where you can set subsampling of image. Also parameter inPreferredConfig can be used to set RGB_565 instead of ARGB_8888 in case when you don't need transparency in images.
The error clearly says that you are trying to use more memory. This directly points to the image sizes. So, you need to resize your images to use lesser memory. One which can be used for this reason is BitmapFactory.Option. Or else go with manually resizing your images take care that it suit all your needs.
Heap size is the amount of memory allocated to an application to
execute.
The heap size for android applications are determined by the device
RAM. For example if the device has RAM of 179 MB, the android
applications will only get the heap size of 18MB.
Find about it more here. more on how to Load Large Bitmaps Efficiently is found here.
As the stack trace says, it's causing OutOfMemory error.
Since the frames are with higher resolution and no.of frames are also more, it's giving this exception.
I use a skin in my app,and load something like 1.5 Mb of images at some of the activities.
This shouldn't be a problem.... 1.5 Mb + default of ~6Mb for the app when loaded... however, things are quite different.
each png I load as a drawable in my layout xmls, is being multiplied by at least 10 from its actual size...., I wrote a sample app with nothing except for a black screen, and loaded it once without anything on it and got native-heap of 5.8Mb, and then loaded it with a small png of 25Kb and guess what.... 6.25Mb.
I loaded my application with nothing but the skin, and it started with 14.5Mb!!!!!!!!
so now I am in the middle of doing a bitmap recycle operation after each and every activity change.
Is this a known issue with android?
png files are loaded with much bigger size inside the native-heap?
is there a solution other than my current plan?
Thanks.
PNG files (as well as many other image formats, such as JPEG) are compressed files, pretty much similar to zip-files. When you load them into memory they will be uncompressed
and take more space consequently.
How much depends on the internal image config, the default is ARGB8888, which takes 4 bytes per pixel. So the memory consumption only depends on the image size, not on the filesize on disk (which can get pretty small. For example: A 500x500 px bitmap consisting of one color has a good compression ratio).
Example for a 500x500 px image is 500*500*4 bytes = 0.954 MB, which is almost one megabyte.
In my app users choose images and program lets users to make changes on images. Since there are a lot of different android devices out there my program crashes on some of devices which less heap size. I want to calculate the best fit dimensions for user's phone so it won't crash because of VM budget. I have added a screenshot from "Picsay Pro" which is making exactly what i am looking for. I do know about the "BitmapFactory.Options" my only problem is to find a way to decide image dimensions which won't let crash the app because of VM budget.
Calculate the Free Space Remaining on the phone:
long freeMemory = (Runtime.getRuntime().maxMemory()) - (Debug.getNativeHeapAllocatedSize());
where,
Runtime.getRuntime().maxMemory() - returns the Total Heap Limit size (in Bytes).
Debug.getNativeHeapAllocatedSize() - returns the Amount of Data already used by your application (in Bytes).
Calculate the size of the Bitmap you are using by this formula,
long Bytes_allocated = (height of the Image) * (width of the Image) * 4;
Compare freeMemory and Bytes_allocated to select the appropiate size for your application.
I actually ended up compressing images on the phone for two reasons. One was upload speeds and another one was heap problems. You can try doing something similar, or at least post the stack trace!
Android outofmemory error bitmap size exceeds vm budget in 2.3.3
i think this compression technique could help
So far I've not found any reliable way to deal with image size vs available memory. The problem is the memory becomes fragmented very quickly, so that you could have 10 MB free, but no contiguous space for a 2 MB image. What is really needed is the size of the largest free space, but there doesn't appear to be any way to get this. Better would be a way to defragment memory, but no such function exist for this either.
Still if your available memory is less than the image, you can be sure you're going to crash if you attempt to use it, so it has some merit to at least check before you use it.
With late-2012 tablets now having 1920x1280 resolution, we now need 20MB of continuous memory for a single background image! It appears some of these tablets are now allowing heaps up to 256MB, but while tossing more VM space seemingly solves it, we really need a memory defragmenter or a way to reserve space.
There is one trick that might help if the image size is not scaled or modified, and each changed image is the same size AND you are limiting your app to Android 3.0+:
Options opt2 = new BitmapFactory.Options();
opt2.inBitmap = mBitmap; // reuse mBitmap to reduce out of memory errors
mBitmap = BitmapFactory.decodeResource(getResources(), myDrawable, opt2);
This will reuse the same memory area mBitmap for the image.