AIR Android runtime memory leak - android

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.

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()

Memory usage analysis using Android Studio

I am trying to understand where my app is using memory, and where I can make it more efficient in this respect.
In the Android Monitor part of Android Studio, I have dumped the Java Heap, and am looking at the generated hprof.
And I see a lot categorized under FinalizerReference:
What is this? How can I understand better what is causing it, and how to keep it down? Looking into the "Instance" panel doesn't help me much... doesn't make much sense.
I have tried looking at this but it's all slightly over my head at the moment.
Also, at the moment the memory monitor is reporting (in the live chart section) an Allocated memory of 10.58 MB. But on my device, in Application Manager > Running Processes, my app is showing a memory usage of 44MB. Why the discrepancy? If it's the ~33MB I want to try and reduce, I'm not apparently even seeing that in Android Studio, so no real hope of identifying what it is?
There may not be much you can do about FinalizerReference memory usage. See this question for more details - basically some objects implement finalize() and these are handled a little differently, such that they can end up sticking around longer. I haven't looked into it too closely, but I suspect that some android sdk objects do this and there's little you can do about it except for maybe tuning up your object caching/recycling to reduce it.
I'm not sure if this would help with FinalizerReference, but one thing I like to do to track down memory leaks is to find suspicious objects' connections to the GC root.
If you're using the Eclipse hprof analyzer (independent of the actual Eclipse IDE; works with hprofs generated by android studio), this is one way to access this:
Overview
Histogram
Right-click, "List Objects"
Right-click an object you suspect is leaking, "Path to GC Roots"
Now you should see a list of nested references leading back down from the gc root to your object.
I'm not exactly sure what is owing to the discrepancy - here is a similar question on that. Apparently the memory monitor tool may only be reporting heap allocations made by Java code, whereas the device reports the entire processes's memory usage.
The Retained Size reported by the Memory Profiler for FinalizerReference is currently a meaningless number, as I argued in my answer to my own similar question.
To summarize: Treating FinalizerReference like any other class when profiling (as Memory Profiler does), leads to repeated counting of the same memory when calculating its Retained Size.
I view this as a bug in Android Studio's Memory Profiler, and have filed this issue.

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 doesn't auto kill/free memory when my app asks for more memory

I have an android app that uses alot of memory doing pixel manipulation. And what I have noticed is that android does not kill programs or free memory in favor of the foreground app. And my app just crashes with not enough memory errors. Right now I have it autodetect how much memory is left and scale pictures appropriately. This prevents crashes but results in poor image quality.
Is there a way to tell Android OS, free up memory as my app is memory hungry. From what I read from android, the OS should do this automatically. But it doesn't appear to do it. Maybe I'm missing something? The iPhone seems as it handles this much better.
Android apps have a hard Java heap limit which varies between devices. 24MB is a typical amount.
So the obvious workaround is to not allocate your big objects in Java... you can malloc your pixel byte arrays from a native C method instead.
However 24MB ought to be enough for anybody, to borrow a phrase, so I recommend you try to rethink your approach too. Perhaps be more aggressive about reusing bitmaps from a fixed-size pool, break your images up into smaller tiles, etc etc.
Avoid using getPixel() and setPixel() too much, it hence results in a really really bad performance, it's already mentioned on Android Documentation.
Also, manage your own memory usage Java, Garbage Collector will function as long as you follow the rule.

Drawables natively leak memory?

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.

Categories

Resources