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
Related
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.
I got primarily 2 issues.
In fact: I made an app which uses neat ui elements. Because of their detail they have to have a fitting resolution for every screen so i do big pictures in drawable-xhdpi, smaller ones in drawable-hdpi, etc...
The problem is: Using such high resolution UI elements slows down the whole app. It's not yet the worst-case but I am really stressed with the fact that I cannot make a "perfect" app which is beautiful and does not lag.
The second issue is: The app really becomes big when considering tablets also (xhdpi images are bigger). Out of compatibility reasons I dont want to make an extra tablet app...
Somebody got some information for high-res problems?
When using large images on android i found the available heap can be a constraint.
As the lower-res images are scaled up the simple drawing-performance itself should not be any problem.
But every image you need to keep in the heap is reducing available memory for everything else you can do without getting onLowMemory callbacks.
There is an option within the Android Manifest to allow more heap on newer devices
android:largeHeap="true"
This will not give you any more heap on most devices but if you try it on a modern device you can see if it makes a difference to decide if memory might be a problem.
It also can help to enable hardware acceleration.
<application android:hardwareAccelerated="true" ...>
Another option is to improve performance on images which you need often.
The BitmapFactory.Options have an inPurgeable which control if the Bitmap is freed when memory is low.
But ... even if memory is a problem it is morelikely that the views have a too complicated layout.
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.
I see that the Heap Size is automatically increased as the app needs it, up to whatever the phone's Max Heap Size is. I also see that the Max Heap Size is different depending on the device.
So my first question is, what are the typical Max Heap Sizes on Android devices? I have tested memory allocation on one phone that was able to use a heap over 40mb while another gave out OutOfMemory errors in the 20's mbs. What are the lowest that are in common use and what are the highest that are on common devices? Is there a standard or average?
The second question, and more important one, is how to ensure you are able to use the resources available per device but avoid using too much? I know there are methods such as onLowMemory() but those seem to be only for the entire system memory, not just the heap for your specific application.
Is there a way to detect the max heap size for the device and also detect when the available heap memory is reaching a low point for your application?
For example, if the device only allowed a max heap of 24mb and the app was nearing that limit in allocation, then it could detect and scale back. However, if the device could comfortably handle more, it would be able to take advantage of what is available.
Thanks
Early devices had a per-app cap of 16MB. Later devices increased that to 24MB. Future devices will likely have even more available.
The value is a reflection of the physical memory available on the device and the properties of the display device (because a larger screen capable of displaying more colors will usually require larger bitmaps).
Edit: Additional musings...
I read an article not too long ago that pointed out that garbage-collecting allocators are essentially modeling a machine with infinite memory. You can allocate as much as you want and it'll take care of the details. Android mostly works this way; you keep hard references to the stuff you need, soft/weak references to stuff you might not, and discard references to the stuff you'll never need again. The GC sorts it all out.
In your particular case, you'd use soft references to keep around the things that you don't need to have in memory, but would like to keep if there's enough room.
This starts to fall apart with bitmaps, largely because of some early design decisions that resulted in the "external allocation" mechanism. Further, the soft reference mechanism needs some tuning -- the initial version tended to either keep everything or discard everything.
The Dalvik heap is under active development (see e.g. the notes on Android 2.3 "Gingerbread", which introduces a concurrent GC), so hopefully these issues will be addressed in a future release.
Edit: Update...
The "external allocation" mechanism went away in 4.0 (Ice Cream Sandwich). The pixel data for Bitmaps is now stored on the Dalvik heap, avoiding the earlier annoyances.
Recent devices (e.g. the Nexus 4) cap the heap size at 96MB or more.
A general sense of the app's memory limits can be obtained as the "memory class", from ActivityManager.getMemoryClass(). A more specific value can be had from the java.lang.Runtime function maxMemory().
Here are the "normal" (see below) heap sizes for some specific devices:
G1: 16MB
Moto Droid: 24MB
Nexus One: 32MB
Viewsonic GTab: 32MB
Novo7 Paladin: 60MB
I say "normal" because some versions of Android (e.g., CyanogenMod) will allow a user to manually adjust the heap limit. The result can be larger or smaller than the "normal" values.
See this answer for additional information, including how to find out what the heap size actually is programmatically, and also how to distinguish between the absolute heap size limit on the one hand and the heap limit that you should ideally respect, on the other:
Detect application heap size in Android
To detect what your present heap utilization is, you could try using the Runtime class' totalMemory() method. However, I've read reports that different versions/implementations of the Android OS may have different policies regarding whether native memory (from which the backing memory for bitmaps is allocated) is counted against the heap's maximum or not. And, since version 3.0, the native memory is directly taken from the application's own heap.
The iffiness of this calculation makes me think that it is a mistake to monitor your app's usage of memory at runtime, constantly comparing it to the amount available. Also, if you are in the middle of an involved computation, and find that you're running out of memory, it is not always convenient or reasonable to cancel that computation, and it may create a bad experience for your users if you do.
Instead, you might try preemptively defining certain modes, or constraints, upon your app's functional behavior that will ensure that it comes in under whatever your current device's relevant heap limits are (as detected during your app's initialization).
For example, if you have an app that uses a large list of words that must be loaded into memory all at once, then you might constrain your app so that for smaller heap limits only a smaller list of the more common words can be loaded, while for larger heap limits a full list containing many more words can be loaded.
There are also Java programming techniques that allow you to declare certain memory to be reclaimable by the garbage collector on demand, even if it has existing "soft" (rather than hard) references. If you have data that you would like to keep in memory, but which can be re-loaded from non-volatile storage if required (i.e., a cache), then you might consider using soft references to have such memory automatically freed when your app starts bumping against the upper limits of your heap. See this page for info on soft references in Android:
http://developer.android.com/reference/java/lang/ref/SoftReference.html
I am developing in NDK. It hangs in Galaxy S3. For testing I put android:largeheap = "true" in Manifest. Then there was no hanging issue.
Is it a good practice to use largeHeap="true"?
Is there any chance that Google rejects my build due to this tag and
how can I prevent my app from hanging without using largeheap="true"?
Short Answer
No, if you need it it is not a bad pactise because it is there for it.
Long Answer
Official doc states
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.
Some developers uses it to avoid OOM excepetion, so if you are using it just to avoid some OOM it is a very very bad pactice.
Never request a large heap simply because you've run out of memory and
you need a quick fix. You should use it only when you know exactly
where all your memory is being allocated and why it must be retained
If you actually need more space it's ok to use it, you can use getMemoryClass() to check the heap and getLargeMemoryClass() large heap.
But if you can avoid using the largeHeap it would be the best way to go, as the official documentation continues:
Yet, even when you're confident your app can justify the large heap,
you should avoid requesting it to whatever extent possible. Using the
extra memory will increasingly be to the detriment of the overall user
experience because garbage collection will take longer and system
performance may be slower when task switching or performing other
common operations. Additionally, the large heap size is not the
same on all devices and may be exactly the same as the regular heap
size. So even if you do request the large heap size, you should call
getMemoryClass() to check the regular heap size and strive to always
stay below that limit.
I also suggest you to have a look here Managing Your App's Memory
Personally I would say it doesn't really fall into the category of either 'good/bad practice' when used correctly.
According to the docs:
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.
If you have done everything in your power to reduce memory usage, and still require it, then it isn't a bad thing to use it.
If your app is hanging, you will need to directly address that - the largeHeap isn't a magic wand that will make problems go away for all devices. This point is made clear from the following extract of the Android Training docs:
[The] ability to request a large heap is intended only for a
small set of apps that can justify the need to consume more RAM (such
as a large photo editing app). Never request a large heap simply
because you've run out of memory and you need a quick fix—you should
use it only when you know exactly where all your memory is being
allocated and why it must be retained. - (source)
I should also add that Google will not reject your app for using it.