How can I gracefully degrade my performance, given limited memory? - android

I've spent the last few days trying to remove memory leaks in my game, resulting in many out of memory errors. I'm on the verge of adding a significant amount of graphics, that while not hugely complicated, will add significantly to the processing requirements of my system, and I'm a bit worried about my memory usage, and I was hoping someone might have some tips for me. I don't want to go below Android 2.1, so please tailor any answers to that end.
First of all, my game consists of:
2 activities, 13 XML files (Some relating to a small part of a layout, some dialogs, and 2 directly related to activities.
A number of drawables, made in Adobe Illustrator and converted to PNG. These are probably large, but not unusually large, and for the most part, only small amounts of them are in memory at any given time.
Quite a few dialogs.
Targeted towards Android 1.6 and above.
I used the newest Admob, and as a result, I have to build against 3.2.
My default heap size for my emulators is around 24 MB.
A few sample images from my game:
What I have learned:
Despite my total app size being only around 500K, I somehow am taking up 24 Megs, as calculated by adb shell procrank.
I have done considerable optimization, but am not seeing large increases in memory.
Using tools to find what is in the Heap typically only show around 7 MB avaliable, with around 3 MB being used. Sometimes, when opening new dialogs and the like, I see an increase, but I can't say that I see it being all that large...
MAT shows that none of my classes are using an unusually large amount of memory.
So, given all of this, my questions.
Is 24 Mb an actual requirement to develop to (1.6+ android)?
Assuming it is, how can I both allow for nicer graphics for systems which can handle it, but not crash and burn for older systems?
What are some common gotchas that I can use to improve my memory usage?

Without seeing your actual code, I can't say if the following will be relevant to you or not. However, it is worth a shot.
If you are not already doing so, you can consider using something called an LruCache. http://developer.android.com/reference/android/util/LruCache.html
Using this tool, you can determine at what point your cached objects (such as Bitmaps) will become eligible for garbage collection. So, if you want to set it at 4mb (for example) the OS will deal with it should it try to grow beyond it. (See docs for implementation details and a good example).
The only downside is that that little gem only came along with 3.2, so you would have to make that your min SDK in the AndroidManifest, or do a check programatically at run time for the api level to determine if you can use it. Pre 3.2 I would say you need to call recycle() on any Bitmaps you are using, but if you have optimized already I would think the chances are good you are already doing this.
This is a nice little snippet about the difference between the heap and native memory. http://code-gotcha.blogspot.com/2011/09/android-bitmap-heap.html It may (depending on what you are doing) help you to understand why you are not seeing the drop in memory you are expecting.
And finally this post from SO should help when dealing with heap size as well:
Detect application heap size in Android
Hope that helps.

Related

How should I address this crashing problem?

I recently created an android application, and after I completely redid my spinner dropdown menus using a custom adapter, some devices are crashing. It's very minimal, like 3 people have experienced crashes ever, but still it's something I want to address if possible because the apps minimum SDK version is as low as 16, so I imagine it's older devices that struggle the most. Attached is a pic of the crash report! This specific device has 2 GB of memory, you would think that would easily be enough to load a spinner with a bunch of low quality images right?
Thanks for the help in advance! This is the crash report: https://i.imgur.com/Wtm5pX9.jpg
The amount of memory the device has != the amount of memory you can use. The OS takes a lot. Other apps take a good amount. And even the memory you can use is fragmented into different pools. Generally "OutOfMemoryException" means out of Java heap memory (out of native memory would be a different crash, for example). Bitmap memory goes into different buckets on different OS versions, they've changed it a few times. So it could be a variety of reasons- you have too large an image that's using insane memory, your have leaks, you have sufficient memory on the device but the heap allocation spiked for some reason, your network layer isn't efficient (if you use Volley to download images its particularly stupid about that). There's not enough info here to actually give you a suggestion. I'd try to replicate it on a simulator with the RAM purposely capped at 1GB or smaller and see if you can reproduce it.

Reduce Android Application Size

I have developed HelloWorld Android Application which just prints Hello World using eclipse and from tutorial https://developer.android.com/training/basics/firstapp/index.html?hl=it,but to my surprise the app takes 2.21 MB of memory. Can you please suggest way to reduce this size to few kb's as this should not take much space, as I haven't added any images or code in it.
An APK is a zip file, you can open it and figure out what's taking the space. If that doesn't hint you enough come back and add this info.
Also, take a look a look at proguard
Edit: Oh wait, I might have misunderstood you, did you mean storage space or runtime memory ? (RAM)
Are you sure you are talking about runtime memory? Even a simple "Hello world" application with no icon from the default Android project has a 10MB heap with 9MB allocated on my phone. Its installed size is listed as 1MB.
I do not know how to reduce memory usage in such a simple app but I can give you some tips to reduce installed size; however, there is a limit to how small you can go.
If you have an icon for all screen resolutions from mdpi to xxhdpi, it will cost you 44KB. I have found the practical lower limit for a usable app to be a little above that; I have a reasonably small app that is only 95KB. However, this is expanded during installation; expect your app to take up to twice the APK's size once installed.
A good way to get rid of space for a small app is to remove the support library. It is included by default in new projects, and takes from 400-600KB. However, removing it comes at a cost - many user interface improvements such as fragments are only supported on older platforms using the support library, so you will either have to restrict the tools you are able to use or your target user base.
Only way i found to reduce runtime memory is to use various optimization techniques. Here is the tutorial Android Dveloper. This tutorial will help you in increasing performance of your application as well as reducing the runtime memory consumption of your application.

Determining available memory for bitmaps

I'm working on a graphical app for which I want to keep an array of bitmaps that are used for Undo operations. The bitmaps are quite large at around 9M each, so I realise I can only keep a few in memory at any given time.
I'd like some way of working out in advance how many I can have.
I've tried various ways of querying available memory, and am being careful to recycle bitmaps once they are not needed, but despite that the app seems to crash with EOutOfMemory.
I don't want to scale down the bitmap, or use RGB565. I just want a reasonably reliable way to figure out how many undo steps I can allow for.
Thanks
EDIT #1
I've continued to try various ways of determining available memory, including those linked to in the comments, but still am having problems.
The strange thing is that my old Samsung I9000 phone doesn't have too many problems creating and accessing lots of bitmaps each 9MB in size, but my newer Samsung Tab 3 dies allocating the 3rd one.
It should have plenty of memory available. I did read something about there being differences in where memory is allocated for bitmaps on Android 3 and above, but don't fully understand it. Could this be what is causing my Tab to die with EOutOfMemory?
EDIT #2
In desperation I decided to turn on largeHeap in the manifest. I know it's not recommended, but it has made the Tab 3 behave more predictably, and it possibly demonstrates something about the underlying problem.
This reminds me of a very common mistake , of putting the image files into the "res/drawable" folder.
Such a thing causes the bitmaps to take much more memory the higher the screen density is.
for example, for a 100x100 image, it would take only 100*100*4 = 40,000 bytes on an mdpi device, but it will take (2*100)*(2*100)*4 = 160,000 bytes on an xhdpi device (4 times more).
however, since the galaxy tab 3 doesn't seem to have a high density screen, i think that you get OOM because the heap size is small for holding all the bitmaps.
check out my post here for some memory and bitmaps tips.
It seems that getting available memory is a bit quirky in Android, but it turned out that my main problem was that on newer versions of Android the memory allocation for bitmaps has changed, and they now easily blow the limit of the heap.
Setting largeHeap in the manifest got me around that problem, but I'm still not sure it's ideal.

How much hashMap operation can be called 'safe' at a time

I am developing an application in which I have a database with 5000 rows with 4 columns.
problem_id (int)
problem_no (string)
problem_title (string)
dacu (int)
I need to frequently query single items in a large scale like 1000 query to fetch problem_no based on problem_id or sometimes only one item.
So I decided to query all the database rows and map them in a hashMap at runtime. I know hashmap insertion/query operation will take only O(1) or sometimes little more, so I only need 5000 operations I think. But how much space hashMap will take in this case? Would android dalvik be able to allocate them without any trouble?
How much space will hashmap take?
It's an implementation detail that can vary between versions, devices, etc. As long as we understand that and look for an estimation only, you can actually measure it very easily. Android SDK includes a powerful suite of memory analysis tools. Check out Eclipse MAT (the best one in my eyes). You can take a heap snapshot when your hashmap is fully loaded, then use MAT to see how many bytes it takes. Make sure you sum up both the hash itself, the keys and the values (if I remember correctly MAT can do the math for you too (it can handle the core collections very well).
Will dalvik be able to allocate?
For the sake of discussion let's say your hashmap takes 1MB of memory. To get a feeling if that's much, we need to understand the constraints of the system we live in. Dalvik limits the max size of your heap. The limitation varies per device. The minimum on very old devices is 16MB. Devices like Samsung Galaxy 2 have about 32MB-48MB and new devices like Galaxy 3 and 4 have more than 100MB.
The biggest memory hog in apps is usually bitmaps. Since every pixel can take as much as 4 bytes, a full screen bitmap can easily eat up a few MB of memory.
With this in mind, a toll of 1MB doesn't sound bad. It's comparable to a using a nice background image :) if your overall memory usage is low, you can distribute it as you see fit. The memory analysis tools (MAT or DDMS) let you know exactly how much memory your app is currently using, so you can easily estimate how much your total consumption will be.
Other thoughts:
Caching things in memory to improve performance is usually a good idea. So your approach is a good one in my eyes (as long as you understand the memory implications).
Since your memory hashmap is an optimization only, you can be extra careful and only do it when you have memory to spare. You can easily measure the amount of available heap (the is API for that) and make your decision accordingly. You can listen to low memory notification events (google about those). And you can even catch OutOfMemoryError exceptions of failed allocations and change your memory strategy in runtime.
You are playing in a field where exact measurements are difficult. Be sure to QA on several devices and several versions of Android. To simulate low memory settings, try to use the oldest devices you can find.
I personally think that you will have absolutely no issues handling what you want in memory. Especially if those things are just primitives (no bitmaps).
I have used queries for up to 10k rows for caching in memory and had absolutely no issues in terms of memory for them.
The issue might happen when you need to process everything. Like how fast is it to get to a specific item, get all realated items etc..
One issue i have come accross was UI related. I tried to just fill an adapter and show it in a list with all 10k of rows which took about 7 seconds to complete. It was long time ago and i don't recall why exactly that happened, but what i am saying is that i would pay more attention to keep processing outside of the UI thread and manage that as much as possible rather than memory in your case.

largeHeap to exceed Android machine-specific max heap size

I'm currently building an Android project that I believe will use quite a lot of RAM, much more than the default max heap size set by devices.
The app will be the only one that runs on our Android machines (they're single-purpose), so I'm not worried about slowing down other processes. I want all the resources possible to go to this one program.
I know that I can use
android:largeHeap="true"
to give myself more room. However, in another post, a commenter suggested that this setting does not override the machine-specific max heap size. Is this true? And if so, is there another way to exceed this limit?
As an aside, I saw some posts that show how to do this natively. Unfortunately, I'm a mere Java programmer and so I have to work within the constraints of Dalvik.
This option is only for Honeycomp tablets ATM.For API levels below Honeycomp the only thing you can do is increase the heap size of all applications (Rooted phone) I haven't actually used is but check this video from Google IO at 06:00. It said that expands the heap size. So probably he is correct and not the commenter you mentioned :D

Categories

Resources