I wrote Android application and it have some strange problems with Out Of Memory exception, which appears randomly. Yes, I know that problems with OOM exception usually because of images, and I used all what I can to avoid this problem.
The only way I could think to find the place where spend the memory is putting the logs with information about memory everywhere. But I really confused about which values do I need.
I used next values:
Runtime.getRuntime().maxMemory()
Runtime.getRuntime().freeMemory()
Runtime.getRuntime().totalMemory()
Debug.getNativeHeapAllocatedSize()
Debug.getNativeHeapFreeSize()
Debug.getNativeHeapSize()
And before OOM exception I have next values:
maxMemory: 57344K
freeMemory: 9581K
totalMemory: 22407K
NativeHeapAllocatedSize: 34853K
NativeHeapFreeSize: 302K
NativeHeapSize: 40060K
lowMemory false
In this question Android Bitmap Limit - Preventing java.lang.OutOfMemory I see that used compeering ((reqsize + Debug.getNativeHeapAllocatedSize() + heapPad) >= Runtime.getRuntime().maxMemory()) ant in this blog some strange information:
Debug.getNativeHeapFreeSize(); The free size is the amount of memory
from the heap that is not being used, because of fragmentation or
provision.
Also I can not understand haw can be OOM exception if (totalMemory: 22407K) much less than (maxMemory: 57344K).
Please help me understand how use this values.
Related
I am facing difficulties to get updated available heap size of application after removing some of the large objects.
My requirement is to free the memory once user reach the specific level of heap size. e.g I am using Samsung Tab3 which has 64 Mb heap size for an application.
Application should't go out of memory while viewing images, hence i have restricted 55 MB as max limit for heap size to grow. I am checking available heap size before view image. If the heap size is greater than 55 MB then I remove the some of the images which are recently viewed, so i can get enough memory to load image.
But the problem is that the, after removing images objects, I got the last increased heap size, which is always greater than 55 MB. I also called gc after remove each image, but doesn't affect.
I want the decreased heap size after removing image object.
if heap has reached 55 MB then on each removal heap should decrease, how to get decreased heap size?
I am using following codes to get available heap size.
/**
* This method is used to get currently allocated heap size to application.
*/
public static int getAllocatedHeapSize()
{
DecimalFormat df = new DecimalFormat();
int size = new Double(Runtime.getRuntime().totalMemory()/1048576).intValue();
Log.d("heap", "debug.memory: allocated: " + size + "MB of " + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576))+ "MB (" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576)) +"MB free)");
return size;
}
/**
* Check whether free memory is available to store new attachment page
* #return true if available else false
*/
public static boolean isFreeMemoryAvailable()
{
int allocatedHeapSize = getAllocatedHeapSize();
if (allocatedHeapSize > ) {
return false;
}
return true;
}
isFreeMemoryAvailable() method goes in infinite because its not getting updated heap size.
Give me a solution as soon as possible.
Runtime.totalMemory() is not related to how much of the heap that is actually used when called. It returns the actual size of the heap. From the documentation:
Returns the number of bytes taken by the heap at its current size.
Removing objects does not necessarily change the heap size.
You could get the actual usage of the heap by doing:
Runtime.totalMemory() - Runtime.freeMemory();
That said, maybe you should look at storing your images in a android.util.LruCache or something instead of doing this management yourself.
There are several aspects to this question:
1) You might get more reliable and detailed statistics using java management beans, e.g., http://docs.oracle.com/javase/7/docs/api/java/lang/management/MemoryMXBean.html among other (MemoryMXBean, MemoryPoolMXBean, GarbageCollectorMXBean)
2) You cannot reduce your heap size from within the java application, you can only reduce your usage of the heap.
3) You might consider the usage of Soft References http://docs.oracle.com/javase/7/docs/api/java/lang/ref/SoftReference.html. This class enables you to keep references as long as the space is not needed otherwise, and collect it only when absolutely necessary. This way you can limit your heap size, and use soft references to keep data as long as possible but do not impede the GC collecting it if necessary.
The phenomenon: First do allocation some big memory blocks in the Java side until we catche OutOfMemoryError, then free them all. Now, weird things happen: load even a small picture(e.g. width:200, height:200) by BitmapFactory.decodeXXX(decodeResource, decodeFile, ...) will throw an OutOfMemoryError! But its OK to alloc any pure Java big Object(e.g. new byte[2*1024*1024]) now!
Verifying: I wrote some simple codes to verify the problem that can download here, press "Alloc" button many times and you will got an OOF Error, then press "Free All", now the environment is set up. Now you can press "LoadBitmap" and you will see its not work on most of Android 2.x phone.(But in the emulator its just OK, odd)
Digging deeper: I try to dig into some dalvik code to find out why, and find a possible bug in function externalAllocPossible in HeapSource.c which called by dvmTrackExternalAllocation who print the "xxx-byte external allocation too large for this process" messages in LogCat.
In externalAllocPossible it simply wrote:
if (currentHeapSize + hs->externalBytesAllocated + n <=
heap->absoluteMaxSize)
{
return true;
}
return false;
Which means once if the native Bitmap allocation size plus the currentHeapSize(NOT the actually allocated size as shown below, in this case, it's keeping the max size of the heap we bumped up but then freed them all) exceeds the limits, native Bitmap allocation will always fail, but the currentHeapSize in Java seems NOT decrease even when 91.3% Java objects' memory have been freed(set to null and trigger GC)!
Is there anybody else met this problem too?
I think this is correct. Its forcing the entire app (Java+native) take no more than a certain amount of memory from the OS. To do this it has to use the current heap size, because that amount of memory is still allocated to the app (it is not returned to the OS when freed by GC, only returned to the application's memory pool).
At any rate, 2.x is long dead so they're not going to fix it there. They did change how bitmaps store their memory in 3.x and 4.x. Your best bet is to allocate all the bitmaps you use first, then allocate those large structures. Or better yet- throw those large structures into a fixed size LRUCache, and don't use the grow until out of memory idea, instead load new data only when needed.
The class Bitmap has the recycle() method, described as:
Free the native object associated with this bitmap...
The reason behind this method is that there are two heaps: the Java heap and the heap used by native code. The GC only sees the Java heap sizes; for GC, a bitmap may look as a small object because it's size on the Java heap is small, despite the fact that it references a large memory block in the native heap.
I had a user comment that after viewing a bunch of images in my app, it crashes (he believes that it is due to out of memory error). I have the following relevant code:
int themeID = mNav[mPos];
String icon = getThemeData(DbAdapter.KEY_ICON, themeID);
ImageView viewer = (ImageView)findViewById(R.id.viewer);
Bitmap bMap = null;
try {
bMap = getJPG(icon + ".jpg");
} catch (IOException e) {
e.printStackTrace();
}
viewer.setImageBitmap(bMap);
That gets reran as the user flips between images. From here I see that you should call recycle() on bitmaps. Do i need to call it on bMap after setting the image? Or is there some way to pull it from viwer prior to setting the next one?
According to the documentation for recycle (if I call it on bMap) it appears I don't need to use it: This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap.
If you need to explicitly call recycle() it probably means that you have memory leak. Calling it is almost never a solution.
Did you try to check your app for potential mmory leak?
To check it you can for example rotate your device a few times and check how the Garbage Collector behaves. You should have something like GC_... freed 211K, 71% free 300K/1024K, external 0K/0K, paused 1ms+1ms in your LogCat nearly every time you rotate. Watch for changes in this part: 300K/1024K. If you don't have memory leaks, the first part should grow and then get smaller after a few GCs. If you have a memory leak, it will grow and grow, to the point of OOM error.
Check out my other answer about a memory leak.
If you're sure you don't have a leak and you're operating on Honeycomb you can increase the heap size accessible for your app like this: android:largeHeap="true" but it's only recommended when you deal with some huuuge bitmaps or videos, so don't overuse it.
i have an Android app that displays alot of images, it works, the images are gatherd from an url, added to a que and gathered by 4 threads,stored in a cache and then displayed in a listview view 4 images for row, there are abot six rows at each time on the screen. There is a total of usually 90 images.
The rows(and imageviews) are always recycled, so the amount of items is always the same and i'm not initializing anything.
This seems to work quite fine, i have always an average used heap size of 13MB.
The problem i have is that at the beginning mi max heap size is quite small and i get GC messages like:
01-20 16:48:39.191: D/dalvikvm(9743): GC_FOR_ALLOC freed <1K, 31% free 12048K/17351K, paused 25ms
but the more i scroll up down the view the heap size grows more and more untile i get things like
01-20 17:02:05.339: D/dalvikvm(11730): GC_FOR_ALLOC freed 544K, 72% free 13871K/49159K, paused 35ms
as you see even if the used is the same the maximum is increased even if i never got to that limit. and the true problem is that at this point i start to get outofmemory errors.
Can someone explain me what's wrong?
Thanks!
What version of Android are you using? If you're testing on pre 3.0 (ie 2.x), the byte arrays that store most of the information in Bitmaps are allocated and stored in native memory. This means that in heap dumps and in the GC notifications, you only see the small amount of memory used for pointers in Bitmaps, rather than the actual size.
For more information check out this google IO talk on memory management and detecting memory leaks: http://www.youtube.com/watch?v=_CruQY55HOk
Also I've worked on several apps doing similar things. My guess is that either your cache size is way too large, or (more likely) the images you're displaying and storing in the cache are much larger than the size you actually want. If you display a bitmap in an image view, the imageview will store the original bitmap in memory, even if it is significantly larger than what would actually fit in the view. Try resizing the images from disk to at least closer to the appropriate size before trying to display them: How do I scale a streaming bitmap in-place without reading the whole image first?
To cache my Images I use Map<String, Drawable> drawableMap. On a OutOfMemoryError I call this function:
private void cacheLeeren()
{
int size = drawableMap.size();
int del = (int) (size * 0.3);
Set<String> s = drawableMap.keySet();
for (String t : s)
{
if (del >= 0)
{
drawableMap.put(t, null);
del--;
}
}
}
I think it's not the best way...but it works ;-)
My guess is that your app reaches a very high peak of memory usage for a short time. It's true that on average you only use 13MB but if your heap grows to as much as 50MB, it means that momentarily you've consumed much more memory than you're thinking.
Let's try to figure out where this is happening. You've mentioned that you're using an LRU cache. This cache frees memory as soon as it fills up. My guess is that you're starting to free memory too late, and this memory isn't freed immediately - since it depends on the system GC. Whenever you're freeing some items from the cache, try to call System.gc() manually.
You've also mentioned that you're calling Bitmap.recycle(). To the best of my knowledge this is useless on Android 3+ because the native heap is no longer used for bitmaps. Since all bitmaps are on the dalvik heap, they will be freed by the GC.. You can't rush this like before unless you call System.GC() yourself.
Another idea for your source of problems is heap fragmentation. See my previous SO answer to a similar issue in this question.
I've read How do I discover memory usage of my application in Android? and a bunch of other answers, but can't quite nail this down...
I have an Activity that will load a file from external storage into memory and do some parsing/manipulation/etc in-memory. Before I load it I want to guess whether or not doing so will cause an OutOfMemoryException and crash the Activity (I understand that exact answers aren't possible, an estimate is better than nothing.)
From the above-linked answer, I came up with:
ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
int pid [] = {android.os.Process.myPid()};
android.os.Debug.MemoryInfo[] mi = activityManager.getProcessMemoryInfo(pid);
// calculate total_bytes_used using mi...
long available_bytes = activityManager.getMemoryClass()*1024*1024 - total_bytes_used;
So, the questions:
1) am I crazy?
2) how to total the values from the MemoryInfo object to estimate the heap usage of the activity/task? (The above link gives an overview of pss/private-dirty/shared-dirty, but not enough info to guess how to do the total.)
3) does Debug always exist or only when debugging?
4) is there a smarter way?
Answers like these: Two questions about max heap sizes and available memory in android seem to imply that there isn't a better way than this?
I know that using less memory is a good thing, and I am. I'm interested to know how to code defensively, here. Seems weird to just wait for an exception to know that you're out of memory.
Thanks!
you may refer to this link.. A complete reserach on the same problem you are facing.
OOMRESEACH