I'm writing a camera app and when I take a picture, I receive a byte [], decode it into a Bitmap and rotate it before saving it to JPEG. I'm rotating the photo using a native library, however the bitmap is still decoded from a byte[] into memory for this (still, allows me to keep 1 Bitmap instead of 2). So essentially there's 1 place in my code where I require a lot of memory and OOM on some devices where heap is low and cameras are stupid-megapixels. Any suggestions how to fix this without on loosing image quality?
I don't think I want to use largeHeap="true"
Should I forget about rotation and just set EXIF?
Also I'm not so keen on trying to 'predict' if I will OOM as the math's not adding up: Android OutOfMemory when GC reports free memory?
Any suggestions how to fix this without on loosing image quality?
Use android:largeHeap="true".
Or, use some other native library that allows you to hand over the byte[] and does the rotation and saving to disk for you, to avoid the Bitmap and any Java-level processing of the huge thing.
Or, if your minSdkVersion is 19, and the rest of your logic supports it, use inBitmap on BitmapFactory.Options to try to reuse an already-allocated Bitmap object rather than allocate a fresh one. This option is available on earlier versions of Android, but for those it has to be an exact match in terms of resolution; on 19+, the Bitmap to be reused just has to be big enough to handle what you are trying to load into it.
I don't think I want to use largeHeap="true"
It may not help (not all devices will give you a larger heap), and there are costs to the user for the larger heap limit. That being said, manipulating big camera images is difficult without more memory, whether that is in the Java heap or represents allocations from the OS from native code.
Should I forget about rotation and just set EXIF?
That's certainly another possibility, though various things, like ImageView, seem to ignore EXIF headers.
I'm not so keen on trying to 'predict' if I will OOM as the math's not adding up
In part, that's because Dalvik does not have a compacting/moving GC, and ART only has one while your app is not in the foreground. OutOfMemoryError means that there is no single contiguous free block of memory for what you are trying to allocate.
You might not have enough memory to create a rotated copy of a large bitmap.
You could instead paint a rotated image of the original.
Furthermore there are things that need to be considered when processing images:
Always load images scaled to the size of the ImageView.
Always recycle your images
Consider using largeHeap=true if you still have issues. Android might be growing the heap size too slowly (see https://stackoverflow.com/a/14462026/1390015).
Related
I would like to load, process and store high resolution image. In spite of largeHeap="true" option in AndroidManifest.xml, when some high resolution image was loaded, OOM exception was occurred frequently.
By googling, I knew that using JNI can load bitmap to native heap on lower version than Android 3.0. If so, how can I use native heap for bitmap on higher version of it? still JNI?
In my opinion, you should decode and process each part of big bitmap instead of process whole the bitmap. It'll help to avoid OOM.
BitmapRegionDecoder can be used to decode a rectangle region from an image. Hope it can help.
I am not sure that what do you mean by "process", but you could use the following library if you need to load large data and then zoom in to extract more details
https://github.com/davemorrissey/subsampling-scale-image-view
hi i am new to android and i have come across some memory management issues whilst using xml to position and design my activity layouts.
most images are around 100kb but vary in size e.g. image 1 will be 512x512, image 2 will be 120x320 etc.
at the moment the images are slowing down my app's performance and sometimes crashing.
Is there a way to reduce the amount of memory an image takes up on an app?
There's a number of steps that applications must go through in order to handle bitmaps sanely.
Small Compressed Size. It's important to balance quality vs. file size for your on-disk (or on-wire) formats. Being able to run PNG files through a lossy pre-processor, or choosing to use WEBP/JPG where needed are critical for each image in your app. Smaller PNG Files covers this more. The problem here, however, is that this doesn't help you with in memory size. Remember when your images are loaded from disk, they are decompressed into 32 bits-per-pixel in memory (in other words, no compression).
Compressed In Memory Format. Android provides the alternate 565 format, which uses only 16 bits per pixel, instead of the 32 bits for the 8888 format. If you're using an image that doesn't need alpha, you should consider the process discussed in Smaller Pixel Formats to leverage loading a bitmap as a 565.
Re-Using bitmap space. Most applicaitons that use thumbnails, only really have 10-20 of them visible on screen at one time (even though there may be thousands to load). The trick here is described in Re-using bitmaps. Basically, once a thumbnail is no longer needed, you can re-use it's space for an incoming thumbnail, rather than allocating a brand new one.
Display resolution. It makes no sense to load a 2MB image, to only display it as a thumbnail. Instead, you should be scaling the image to the resolution of what it'll display at, on the device. I discuss the most efficient way to load these images in the other SO post.
In general, Libraries like Picasso and Glide do a good job at providing APIs that make all this easier; but they are still going through these same processes under the hood.
You have 3 solutions you can do:
1st Solution:
Add in your AppManifest.xml in your application tag:
android:largeHeap="true"
This will try to prevent your app from causing OutOfMemoryError, but use it with caution.
Documentation: Whether your application's processes should be created with a large Dalvik heap. This applies to all processes created for the application. It only applies to the first application loaded into a process; if you're using a shared user ID to allow multiple applications to use a process, they all must use this option consistently or they will have unpredictable results.
Most apps should not need this and should instead focus on reducing their overall memory usage for improved performance. Enabling this also does not guarantee a fixed increase in available memory, because some devices are constrained by their total available memory.
2nd Solution:
If your images' file size are large, you can minimize them by using this online tool: http://compresspng.com/
3rd Solution:
You can use BitmapFactory for loading your images. Here is the Android Developers documentation: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
I am Working with one android tablet application in which lots of work with Images.
i have to load hundred of large bitmap images in scroll view. one image is around 1Mb to 3 Mb.
i have already scale images using bitmap factory and sample size, and also load all the images in Async task.
i am loading all the images from SD card.
Still facing OUT OF MEMORY issue after scrolling some images.
any help would be appreciated.
thanks in advance.
hi hope your solution.
you can user Univarsal Image Loader. This is better api for image download and store in catch. and get from catch. it's a great api for image operation.
this case is often come while we getting bitmap so just use lazy loading. just take a look on this example
http://sunil-android.blogspot.in/2013/09/lazy-loading-image-download-from.html
To prevent your application from soaking up CPU time without getting anything done, the JVM throws this Error so that you have a chance of diagnosing the problem.
Its because of large bitmap memory in stored in native area
so it better i suggest you use libraries like Universal Image Loader or
Bitmap Fun from android
You have to find out when the OOM error occurs. Is it when you have too much bitmap cache in memory without releasing or you just meet it when you're decoding certain bitmap?
For the first situation, I think you should manage your bitmap cache yourself or using some effective 3rd-party library which mentions above.
For the second situation, I've met it on some low-performance mobile(usually with 512MB or less memory), when you decode a bitmap to requested size, it may needs a rather large memory to store the bitmap, for 240dpi devices, it's about 800 * 480 * 4 = 1.5MB, however you may fail to allocate that much memory on some machines cause they may have strict memory manage strategy to prevent that much memory allocation. You should just catch the OOM error and continue rather than get a crush.
Loading a bitmap in 1280x800 display will take 1280x800x4 byte (~4MB) memory. Java heap size is limited (~50MB) so you can not use lots of large bitmaps in your app. Using cache and reusing bitmap objects are necessary while working with bitmaps but another useful trick is to use larger hip size! to do so, add android:largeHeap="true" to Application tag in your manifest. It increases hip size to 4 or 5 times larger (~250MB) than normal. I hope this help other people reaching this thread while they search!
I am trying to analyze the heap dump of my android app. The analyzer MAT shows
me this message
The class "android.content.res.Resources", loaded by "", occupies 12,084,776 (87.38%) bytes. The memory is accumulated in one instance of "java.lang.Object[]" loaded by "".
What do I do about this? I want to avoid OutOfMemoryError.
As almuneef mentioned, this is mostly seen when the size of your resources is large. Are you trying to load a bitmap?
You might want to look at Android memory allocation
Your problem is due to the large resources. Just reduce the size of your resources and your issue will be fixed.
If your resources are in .png format then change it to jpeg and you can easily reduce the quality of the image (size also reduces considerably for even a small loss in quality)
Hope this will fix your out of memory issues
Don’t worry about “android.content.res.Resources”,It was loaded by system,
I want to display a bitmap read from the SD card at actual pixel size in Android.
I can't assume anything about the bitmap, other than Android supports its image format. The bitmap might be huge.
Seems simple enough, but when you factor Android memory limitations it gets much more complicated.
Any ideas?
Edit: Attempting to load a large bitmap gives an out of memory error because Android is not able to allocate enough memory to decode it. You can load a scaled down version of the bitmap, but this is not useful to show the bitmap at actual pixel size. The question is about how to show a large bitmap on Android while staying within the app's memory constraints (most likely by loading it in chunks).
Edit 2: The bitmap might be huge, but within the realm of reasonable. I'm talking about user images, not HD Nasa pictures.
The managed code (Java) has memory limits of 16/24/32MB even if your device has a lot more free memory. I'm currently working on an application which needs to do this and the solution is to allocate the bitmap in native code (NDK) and then render views of the image into a Java-allocated bitmap which is the size of the display. In native code you can allocate all available memory of the device, but for some reason the virtual machine limits it.
Since android 2.3 (Gingerbread, API Level 10), you can use the BitmapRegionDecoder. I don't know any solution for older android versions. (and I've been looking for it for my EmailAlbum app)