I have application which in one method needs to load 2 large bitmaps, mask bitmap and perform masking process. It works fine until device has 16 MB ram limit.
My question is - are there any libraries that will allow using internal storage on specific method in case of overflow on heap memory?
If the bitmaps are used for display on the screen try downsizing them on decode.
BitmapFactory.Options.SampleSize
If that is not an option you can try sacrificing some performance with
BitmapFactory.Options.inPurgeable = true
Related
I am new to android and my app sometimes resulted in an outOfMemoryException. Therefore I have to check how much ram my app is using and try to reduce it.
Two questions:
How to know the ram size that my app is using?
Normally, what is the safe threshold for an app's ram size so that it would not cause an outOfMemoryException ?
Thanks a lot for your help!
Check out Android Studio's in-built memory monitor. that you will find under
Android Monitor > Monitors
and for the second part of your problem you can use ActivtyManager class' getMemoryClass () method.
from the android doc..
Return the approximate per-application memory class of the current device. This gives you an idea of how hard a memory limit you should impose on your application to let the overall system work best. The returned value is in megabytes; the baseline Android memory class is 16 (which happens to be the Java heap limit of those devices); some device with more memory may return 24 or even higher numbers.
Check that the image size is smaller than the available memory before attempting to load it. So the most efficient way to handle OutOfMemoryException is to architecture your application in such a way that it never attempts to load lots of data into memory in order to avoid the exception.
Before loading images into memory compress your images using
Bitmap original = BitmapFactory.decodeStream(getAssets().open("1024x768.jpg"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
original.compress(Bitmap.CompressFormat.PNG, 100, out);
Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));
Log.e("Original dimensions", original.getWidth()+" "+original.getHeight());
Log.e("Compressed dimensions", decoded.getWidth()+" "+decoded.getHeight());
1.How to know the ram size that my app is using?
This question quite hard to answer. Different type of apps requires different memory.
2.Normally, what is the safe threshold for an app's ram size so that it would not cause an outOfMemoryException?
Different devices have different threshold. You can normally use
Runtime rt=Runtime.getRuntime();
long maxMemory=rt.maxMemory();
Log.i("maxMemory:",Long.toString(maxMemory/(1024*1024)));
to see a size of maxMemory you can use. But this is not exactly.
I am trying to find an efficient way to load a Bitmap from a file containing an arbitrarily large image, place a watermark (a logo) over it, and save it back to file.
I am aware of the memory problems that come with dealing with a large bitmap on Android. I don't want to load a smaller sample of the image, because I need to keep the same quality when saving it back to file.
Any help is appreciated.
Using BitmapFactory.decodeFile(File) leads to OutOfMemory issues when decoding large pictures
OutOfMemoryError occurs because there is no single block of heap space big enough for your request. The Dalvik garbage collector is a non-compacting collector, and so the heap will get fragmented into lots of smaller blocks of memory.
If all of the pictures will be the same resolution, and your minSdkVersion is 11 or higher, then allocate the Bitmap for it when your process starts up (e.g., in onCreate() of a custom Application class), and use that with inBitmap on your BitmapFactory.Options. Your attempt to allocate the Bitmap should succeed early on, before your heap gets fragmented, if the image can fit in the heap in the first place.
If they will not all be the same resolution, but you know the maximum resolution, and your minSdkVersion is 19 or higher, then do the same thing as I describe above. Android 4.4 extended inBitmap to support a Bitmap that is the same size or bigger than the image you are loading, whereas before it had to match the size exactly.
If none of that is possible:
Use android:largeHeap="true" to get a larger heap on API Level 11+ devices, or
Move your image-processing logic to the NDK, as native memory allocations do not count against the Dalvik heap limit, or
Move your image-processing logic to a dedicated short-lived process, so you get a clean separate heap at the point in time when you need to process a particular image
Those latter three options have costs to the user in terms of the system RAM consumption of your app and other effects.
Describing background, as I may just have a terrible approach to the problem - self learning.
I'm writing an app for android, and testing it on default AVD, which is set to WVGA800 with 512 'device ram size' and 240 'Abstracted LCD density'.
I have some images, and I put them into drawable-hdpi.
There are 458 KB (not MB) worth of images in that folder.
All images are in PNG format.
The issue is that when I try to load my biggest image (used for background), it throws: java.lang.OutOfMemoryError
This is the call to load the image:
BitmapFactory.decodeResource(status.getResources(), R.drawable.background);
This is identical to how I load the rest of images (33 in total).
It makes sense to me, that it would run out of memory on biggest image, but my total size of folder is 458 KB, so I wouldn't expect to run out of 512 MB Ram set on device.
I never unload any images, I keep them loaded, and use as needed.
I wrote a different app before, where my total size of images was 563 KB with 82 images total, and I didn't have this issue (using the same AVD). In fact the prior app used to make a couple of copies of each image by flipping it, and still didn't run out of space. Current app is failing on initial load - before much happened.
Could someone point me at what the issue could possibly be? And how I can solve it, or maybe mention if my approach is wrong (self-teaching myself from examples)
I'll give you some hints on how i manage to lessen that problem
If you plan to support all devices, put all your resource into the xhdpi folder. especially the background
File size != memory size
Keep in mind a few things:
Your application has a memory limit (this depends on the android version). You don't get all the device memory. I think that first android version have a memory limit of 16mb.
The size of the file doesn't represent the size of the bitmap in memory. For example a 32bit ARGB bitmap will take 32*width*height bits
If you are dealing with big images then scale them first. Calculate the size you need (this will probably be the size of your ImageView) and load a resized copy of the bitmap. You can do this using BitmapFactory.Options
Yea, this is a pretty common problem. So in older versions of android OS, the bitmap was loaded into native memory and not the JVM. The garbage collection process would really have 2 cycles. One to clear out the memory in the JVM and the other to clear out the memory in the native memory (for bitmaps). If you want to work on older devices, you will need to handle this situation by either recycling your bitmaps Bitmap.recycle() or calling System.gc()
There are two problems that you might be hitting:
1. You have other bitmaps that are un recycled.
2. You really are running out of memory because that single image is too big. (Make sure the other images are correctly recycled or gc'd so that it doesn't add to the memory footprint). In this case, no much you can do.
ALso, as mehmet suggested, you can read this
I am manipulating relative large images, about 5MP and sometimes even more. I need two copies of the images in memory for manipulation.
Now, the loaded images consume a lot of memory, more than available by the default Android heap which is 16MB respectively 24MB which results in the following error:
11-20 18:02:28.984: E/AndroidRuntime(7334):
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
I need full resolution, thus downscaling while loading the images does not help.
What's the best solution to get over this problem? Are there built-in methods to dynamically load only chunks of bitmaps from storage? And can someone give me some hints how I can overcome the memory problem, e.g. by using specific caching strategies?
Regards,
You can allocate more memory in the ndk. You'd have to write native code to manipulate the images, or you'd have to figure out a way to allocate the image memory in native, then pass it back to Java.
Bitmap/Canvas use and the NDK
Another option might be to load a single image into memory, and break it up into chunks for processing. Save those chunks out to the file system. So, say you 2 large images. You load the first image, break it into 4 parts, save them, load the second, break it into 4 parts, save those, then load part #1 for each image, and do your thing. That implies you know that neither individual image is larger than the heap max, and that what you need to do is (basically) pixel level and doesn't need access to surrounding pixel data (you'll run into trouble at the edges if you need neighbor pixel info).
Without downsampling, splitting, or ndk, I don't know how you'd get more image data into memory. Perhaps lowering the color info. We do this in a product. Represent each pixel as 16 bits rather than 24 or 32. Our product is functional rather than "pretty", so the loss of color info wasn't a big deal.
You should watch this video on memory management: http://www.youtube.com/watch?v=_CruQY55HOk
At about 6 mins into it he covers the LargeHeap manifest option added to HoneyComb.
I am working on an application for android and we since we have lots of graphics, we use a lot of memory.
I monitor the memory heap size and its about 3-4 Mb , and peeks of 5Mb when I do something that requires more memory (and then goes back to 3). This is not a big deal, but some other stuff is handled outside the heap memory, like loading of drawables.
For example if I run the ddms tool outside eclipse, and go to sysinfo, I see that my app is taking 20Mb on the Droid and 12 on the G1, but heap size are the same in both, because data is the same but images are different.
So the questions are:
How do I know what is taking the memory outside the heap memory?
What other stuff takes memory outside the heap memory? Complex layouts (big tree) ? Animations?
Thanks
Daniel
Bitmap objects takes a quite alot of memory.
Ex. if your app downloads a 10KB jpg from net and use BitmapFactory to decode it into a Bitmap that bitmap objects needs about 30-100KB memory, depending on the resolution of your image. 3bytes for each pixel (1 byte for each color)
And yes, all kind of object uses memory, like LinearLayouts, ImageViews etc... If you are creating and destroying many of these objects, ex. as you scroll / page through your images, there will be memory leaks. The gc() does not handle so-called short lived objects as fast as we would like.
*Keep the number of view objects at a stable level**, and recycle them instead of destroying and creating new ones.
REf: http://developer.android.com/resources/articles/track-mem.html
If your app reaches 20MB in memory, it may FC as the BitmapFactory is trying to decode the next image.
One obvious candidate is off course off-screen bitmaps (double-buffering by android?), since the screensize has ~4x as many pixels on the droid.