Drawables natively leak memory? - android

I'm reading this question because I have to load a ton of downloaded resources into an app I'm writing, and was curious if there was a dramatic performance hit in doing so [vs. having them in the .apk], and the "correct" answer to the question implies that while there is no performance degradation, you have to worry about releasing the memory back when you're done with it, lest it leak.
Can anyone confidently confirm or deny this? My impression was that a loaded Drawable was GCed just like everything else when the Activity it was cleaned up. I'd very much like to know if that's not true, and what the most reliable way to manually collect the memory in said instance is.
Also, does anyone know if there's a noticeable performance hit in loading images from the SDCard, vs. from the phone's memory. I'm not an electrical engineer, so, intuitively, it seems like since this is all solid state memory, it should all get read at about the same pace, but I'd love to get a definitive answer.

Quick answer:
Bitmaps take two passes of the garbage collector to clean up. The first pass releases the Java object, the second pass the native pixel data. They don't leak, but you can run out of memory between when you null the pointers and the GC hits its second pass over them. This is true no matter what resource they come from. It's always a good idea to call recycle() on a bit map when you're sure both you, and the system, are done with them.
Gingerbread is particularly bad in dealing with out of memory issues and bitmaps due to a bug in the Dalvik VM.
In my experience, loading images out of the apk is MUCH faster than off the SD card.
1) They're zip aligned in the apk (if you align your apk, which you should)
2) Different phones have different access times to the SD card. The general rule is, if it's on the sd card, it's going to load SLOWLY. You can get away with loading drawables from the internal memory on the main thread (even though it's a bad idea). You cannot load anything from the SD card on the main thread. Ever :-\
If I were you, I'd be as lazy as possible when loading images, I'd keep them in the apk if possible.

Related

Free RAM in Android

I'd like to know some simple code that allows for freeing used memory that is no longer needed, in a similar way as a lot of memory freeing apps do.
Yes, I'm aware that this shouldn't be neccesary because Android manages memory on its own, but it looks like what's causing a non desired behavior in my app is having a lot of opened app occupying memory, so I think this is worthwhile to try, and check if the error happens any longer.
Could anyone hand me such a code? I'm not able to find any.
What I gather from the article is that you don't need to do anything to reclaim memory, but you can make garbage collection happen quicker and at specific times. What this means to me is that any arrays, Lists, large objects, etc. should be set to null when you are done with it. Granted, this should be done automatically when you leave a method or a View, but in case you are in a long running loop or staying on a page with lots of data hanging around, you can clean it up a little faster.
The Android Runtime (ART) and Dalvik virtual machine use paging and memory-mapping (mmapping) to manage memory. This means that any memory an app modifies—whether by allocating new objects or touching mmapped pages—remains resident in RAM and cannot be paged out. The only way to release memory from an app is to release object references that the app holds, making the memory available to the garbage collector. That is with one exception: any files mmapped in without modification, such as code, can be paged out of RAM if the system wants to use that memory elsewhere.
https://developer.android.com/topic/performance/memory-overview
You can also check your memory usage to see if that's really the problem. This is linked in the article above, but I thought I'd pop it out so it's easier to notice.
https://developer.android.com/reference/android/app/ActivityManager.html#getMemoryClass()

AIR Android runtime memory leak

Good day,
I am developing an adventure game in AIR for Android. I am instantiating levels from the library (movie clips), each containing at least one HD resolution bitmap.
When the game starts, it occupies about 150MB of memory, including the AIR runtime and the SWF. Out of this 150MB the SWF is about 12MB at this time.
As the game progresses the memory consumption of the AIR runtime increases, while the memory used by the SWF remains at around 15-20MB. When the total memory consumption reaches about 350(!)MB, the OS intervenes and kills the app.
I was careful to reuse objects whenever I could, and nullify any unused objects to make them eligible for GC. GC seems to be working as it should, as the memory used by the SWF remains steady around 15-20MB. I can see it drop from 20 to 12 from time to time when GC kicks in.
Things I've tried:
Removed all cacheAsBitmap and cacheAsBitmapMatrix properties.
Exported each level into a separate SWF and loaded them from there instead of the library.
Forced the GC hack just to see if it has any effect.
Fiddled with System.pauseForGCIfCollectionImminent(n) with different values for n.
Tried different acceleration modes (direct and auto) thinking maybe the GPU is at fault.
All failed, memory consumption just runs away.
This happens only on Android. On a PC everything is fine, the whole thing takes up about 250-300MB, and this number remains steady, no matter how many levels I load one after another. Didn't have the chance to test on iOS yet.
I would really appreciate any ideas or insights into how to make this problem go away.
Thanks.
1) Easiest way to find memory leak is to use Adobe Flash Builder. Just run profiling.
2) Also good way to exclude leaks in future: create function which will be used for "cleaning". E.g. it will null all local variables of instance and so on. Something like usual c++ destructors. Then, before nulling your object, just call this method.

android:largeHeap="true" convention?

I'm writing an image gallery app and I keep running into out of memory errors. I cache all my images but the problem occurs when I try switching between images really fast. I'm assuming the app is allocating memory faster than the GC has time to free them up (because the crash doesn't happen when I switch images slowly).
After banging my head against this problem for days, I finally decided to give largeHeap setting in the manifest file a try. After this setting, my app no longer crashes no matter how fast I switch between images.
Now, I want to know if there is any convention or general guideline to using largeHeap setting because it probably wouldn't make much sense if, say, a note taking app used largeHeap. Generally speaking, what apps are a good candidate for largeHeap setting?
Thanks
Generally speaking, what apps are a good candidate for largeHeap setting?
Ones where you can justify to the user why you're forcing all their other apps out of memory, to give you an outsized amount of heap space.
Personally, I would not consider "an image gallery app" to qualify. AutoCAD, video editors, and the like would qualify.
With respect to your memory management issues, make sure that you are using inBitmap on BitmapOptions when running on API Level 11+, so you recycle existing buffers rather than go through garbage collection. Particularly for an image gallery, where you probably have a lot of fairly consistent thumbnail sizes, recycling existing buffers will be a huge benefit. This can help both overall memory consumption (i.e., you are truly out of memory) and memory fragmentation (i.e., you get an OutOfMemoryError with plenty of heap space, but no single block big enough for your allocation, due to Android's frakkin' non-compacting garbage collector).
You might also consider looking at existing image cache implementations, such as the one that Picasso has, to see if there are some tips you could learn (or possibly just reuse).
First, make sure you aren't loading larger bitmaps than necessary:
Load a Scaled Down Version into Memory.
Then, before trying largeHeap, try to free the memory quickly yourself:
If you call bitmap.recycle(); as soon as you are SURE you will not use a bitmap again, then the bulk of that bitmap's memory will be immediately freed. (When the GC gets around to it, all that remains is a tiny object.)
On newer Android versions, there are alternatives (instead of recycle) that may be more effective:
Managing Bitmap Memory
Personally, I still use recycle often, especially if I might be loading a different size image, so can't reuse the existing one. Also, I find it easier to code "unloading" of old media separately from "loading" of new media, when changing to a different fragment or activity:
As leave the old fragment, all old bitmaps I recycle (then, if reachable from a static field, set to null).
The rule of thumb for whether to use largeHeap, is to consider it after you've tried alternative ways to reduce memory usage.
Code your app so you could turn it off again, and still run.
For example, monitor your memory usage, and load "scaled down" bitmaps if memory is tight. Will the user really notice if a given image is not at their device's "retina" resolution?
Or if it is an older, slower, device, will largeHeap make your app feel unresponsive / jerky? If so, can you drop resolution even further, or show fewer bitmaps at one time?
Get your app to work in all circumstances, without largeHeap [by techniques mentioned above]. NOTE: you can "force-test" running on tight memory, by allocating some "dummy" bitmaps, and hold references to them in global fields, so they don't get freed.
NOW you are able to evaluate the trade-off, as it affects YOUR app:
When you do turn largeHeap on, use your app heavily - are there places where it is now "more sluggish", or animations "stutter" or otherwise seem less smooth? BE SURE TO TEST ON AT LEAST ONE OLDER DEVICE, AND ON ONE HIGH_RESOLUTION DEVICE.
You might be seeing long GC times, due to the larger heap.
OR you might conclude that largeHeap is working well for you, and now you can confidently say that it is the best choice in your circumstance.

Android OutOfMemoryError when parsing csv file

I have an app that downloads a csv file online then saves it locally so the app will work even if it is offline. My problem is when the user closes the app then opens it again immediately, the app hangs while parsing the saved csv file and throws OutOfMemoryError. However, I noticed that when I open the app again after a few minutes it works just fine.
The downloading, parsing and saving are done on separate threads.
What can be the solution to this?
One possibility: out-of-memory errors can have more to do with an overworked GC than with an actual shortage of memory. If you allocate large pieces of memory, then free them, then allocate even larger pieces, you get to a point where you have a lot of large bits of free memory taking up space but unusable because they're not large enough. The GC is frantically trying to move things around and merge these pieces into one contiguous block for the next allocation, but rather than look bad because it's taking too long, it will just throw an OutOfMemory exception, even though 90% of memory is theoretically available (and will be available if you can give it a minute).
In your case, I'd suspect ArrayList. It keeps an array of references. As you add entries, it adds to the array. When it runs off the end, it allocates a new, bigger, one and frees the old one. These discards pile up if you keep it busy. Hashtables have similar problems. LinkedList and TreeMap don't, because they work with small bits of memory.
I don't know too much about Android, but I'm guessing the app doesn't really close when you close it briefly, so when you restart it it's the same free-memory-fragmented execution as before. If you wait a while it may be a new execution. Even if it's not, the GC has had time to clean things up and you're fine.
The solution you want is probably to force a garbage collection (System.gc()) each time you "start up" your system. It gives the GC a chance to put everything in order before allocating space for you, and it won't take long. In a sense, you're giving the GC permission to lock up your program for half a second, which it would not do on its own. (And if it did, it would pick an awkward time to do it--while the user's entering text, say.)
Avoiding large arrays by using linked collections is another solution, but arrays are fast and when you can spare a half-second of the user's time there's no reason to switch.
Hope this helps. If it's not the problem this time, maybe it will be next time.
Addition: Unfortunately, System.gc() is just a "suggestion". It may not be doing the job we hoped it would do. Or you may be getting into trouble after the call. The other big fix I should have mentioned before would be to set the initial size on ArrayList very large, if that is what your are using. Making it two or three times the size it needs to be will probably save you ten times that amount of memory over a run--and save time, too. This works for any array-based structure (hash tables and plain arrays). Beyond that, pointer-based structures like LinkedList will not have this problem if you can get around their disadvantages.

Out of memory error: vast bitmap

My activity has listview and (apart from all other stuff) loads images from web and displays them in listview. I have access to 5 android devices: 2 HTC desire, LG P-350, one more phone and a tablet. Normally, everything works fine, but being launched on one of HTC desire, app tends to crash with NullPointerException, which is due to out of memory error (I guess so), this is the output:
05-03 14:41:23.818: E/dalvikvm(843): Out of memory: Heap Size=7367KB, Allocated=4991KB, Bitmap Size=16979KB
Later, logcat outputs stack trace of nullpointerexception where one of my static variables suddenly becomes null (the variable is initialized in app's root activity, is used across the app and for sure is not nulled in code). I suppose, it is nulled by system due to lack of memory.
As far as I undesrstand, system tries to allocate bitmap as large as 17mb - I'm sure loaded images cant be that big. They are 100*70 jpegs and any of them weighs far less than 1mb.
Another thing I dont understand is why I get this error only on one device - other devices work fine.
To my mind, this looks very strange and I can find no clue, I need advice.
The reason is simple: the memory is not holding your JPG data per say, but rather its decompressed equivalent, which, needless to say, takes a lot more RAM space than the source files... Note that this 17 mb limit is for all your loaded bitmaps at once, not necessarily a single one.
I had to fight with similar problems in one of my programs (a custom Tile loader for a Mapquest Android API MapView object), and I ended up having to call the recycle() method of my bitmaps whenever possible, as well as manually oblige the system to garbage collect at strategic locations using System.gc()...
Sorry to not be the bearer of the best news...
You might solve your problems using the same strategy as I did: I essentially cache the loaded bitmaps in hard storage such as my external SD card, and reload them on the fly when needed, instead of attempting to hold everything in RAM.

Categories

Resources