Maximum size for android application? - android

I'm having a hard time finding an updated answer for this.
So far I've been aiming to land my resources <16mb. But This is getting harder and harder the further along I get, I mean, a 1000x1000 .Png-file uses around 1mb.
Obviously I'm aiming to keep it as small as possible, but at what size should I start worrying? Planning on releasing for android >2.1

The lowest heap space you will ever get is 16 MB, IIRC. It is possible that you may be given upto 64 MB, or even more, but you should always try and operate under 16 MB. Remember that if you can possibly get more heap space, and you do try and use it up you could end up displacing other apps from the memory, and cause some minor or in some cases major problems to users.
It's not that you can't get more space. The fact is that you should make your app as good an Android citizen as possible, and be as friendly to the device as you can.

You can get the maximum healp size with:
Log.d(TAG,"Memory Class: " + ((ActivityManager) getSystemService(ACTIVITY_SERVICE)).getMemoryClass());
Log.d(TAG,"Heap size: " + Runtime.getRuntime().maxMemory());
If you are loading big PNG files, you should look for the best practices on how to handle big images on Android, but have in mind that some of your options for the BitmapFactory have huge impact on how the image is loaded:
-inScaled when set may increase the bitmap memory size by a factor 2 or 3 in new devices with high screen density,
-ARGB type may go from 2 bytes per pixel (RGB_565 and ARGB_4444) to 4 bytes (ARGB_8888), so a factor of 2 again.
good luck.

Related

Huge byte[] in my app after HPROF

From time to time, especially when implementing new functionalities in my app, I use DDMS + HPROF to analyze memory and heap use. As the App doesn't seem to have any performance-ANR issues and everything works smoothly, initially I didn't care about it - but now, as I see it's approximately always the same size, I'm wondering what the damn can it be.
Everytime I run a HPROF, I check the Leak suspects tab. There's always an android.graphics.Bitmap instance that takes approximately 25% of all the used heap.
I wanted to know a bit further what's that about, so I opened the dominator tree, and saw this:
So esentially there's a huge byte[] instance that is retaining a lot of heap, and never gets released. According to this, I copied the value of that byte[], dumped it into a .data file, opened with Gimp, and there's the result:
So basically, it looks like the "alpha(0)" part of a PNG image. Having in consideration the following facts:
All my image files are <8K in size
Just some of them are PNG - the remaining I was able to convert to JPG, I did
No matters if I add further images, the size of that byte[] has been always aproximately the same from the beggining of the app (4 months ago)
To debug it, I tried to remove any image file from the drawable and drawable-xxx folders and run the app without any drawable resources, and the byte[] was still there
I removed almost all layouts and let just the basic funcionality, and same result
In the Dominator tree, the root class is android.graphics.Bitmap
Anyone knows what it this byte[] and if I should do anything to free it up?
Any help appreciated!
Just to clarify a few things:
Images/drawables in your app are used in memory in the form of android.graphics.Bitmap.
As of Android 3.0 (API level 11), the pixel data is stored on the Dalvik heap along with the associated bitmap. (Managing Bitmap Memory)
"huge byte[]" is probably an overstatement as it is just over 1MB of heap space.
The Leak Suspects report can be helpful, but in this case it isn't telling you much considering that its largest suspect is just over 1MB of memory. Modern devices are offering 64MB+ heaps.
Let's do the math for the memory requirements for this bitmap. This bitmap is taking up 1,127,584 bytes on the heap. If we were to assume this bitmap is configured using ARGB_8888, each pixel is using 4 bytes, which means your image contains 281,896 pixels (or roughly 530x530). Does this sound unreasonable for what you are doing?
Also, consider the way Android scales across the different "buckets" for drawables: mdpi, hdpi, xhdpi, etc. Let's say you have a 200x200 image in the mdpi bucket and you are opening the app on a xhdpi device. This image will be scaled to be twice as large and will have a on-device resolution of 400x400. So while the 200x200 image may not take much heap space (200 x 200 x 4 = 160 kb), the 400x400 image will require a relatively larger amount (4x) of heap space (400 x 400 x 4 = 640 kb). For more information on this, see Supporting Multiple Screens.
A nice tool for quickly computing differences with the image buckets: Android DPI Calculator
You said you removed some of your drawables, but what is left? Have you considered drawables that may be coming from external libraries?
To answer your final question: Anyone knows what it this byte[] and if I should do anything to free it up?
I would say: This small amount of memory on your heap is nothing to be worried about. If it is bothering you, keep an eye on it and make sure it isn't growing beyond what seems practical. If you still suspect a memory leak, navigate between screens and watch to see if the heap continues to grow. Assuming you are not caching bitmaps, the heap should maintain a consistent/predictable size when navigating back and forth between two screens
As a side note, DDMS makes it very easy to monitor heap size on the fly. No need for HPROF dumps until you are ready to dive in. Have a look at Using DDMS. Take special note of the "Cause GC" button as it will be needed to trigger the update of the initial heap size.
-- UPDATE --
To further answer this, one unsupported suspicion I have is that some of the app's assets (system assets/textures?) are loaded into your app's memory space. Have a look at slide 64 here: What's new in Android 4.4.
Android 4.4 now generates a single texture containing all the framework assets, shared by all processes. This saves a bit of memory in every process but it also helps batching and merging drawing operations to optimize applications automatically.
This seems to imply that memory is used for system bitmaps/drawables in each app running a version prior to 4.4. If this is the case, I would question if this 1MB is that space. I wonder if you could run your app on a 4.4 device/emulator and see if the same memory is used.
As another test, have you tried inspecting memory usage on a barebones app (all drawables removed, etc)?

Android Fatal Signal 11 from XML

I am creating an Android app and I have yet to run out of memory until just now. The part that is confusing is it was not a way I would expect to run out of memory.
I simply added a new Linear Layout to a layout xml file. It had a background of an image that was 40kb large. The other images that were loaded were approximately 12kb with the background being much larger at 120kb. When this image was loaded I would receive a Fatal Signal 11 on runtime. If I removed the background from the layout it would work fine. I then changed the image to be much smaller, it was (2000x600) before so now it is 14kb. It now works fine. It is clear that the extra 26kb was causing a problem...
What kind of precautions should I take to ensure this doesn't happen again. Obviously I would like quality images and the 2000x600 might be excessive as it's an app for a phone but what guidelines should I follow?
Is there a memory usage cap that can be extended or that I should look to stay under? Also, if I loaded many images on a scrollview will this cause the app to crash? I have had many images loaded at once but have never had it crash before, I'm just confused as to the error being caused by very little memory usage. (In todays terms at least.)
Regards,
Jake
Images do not consume the same amount of memory in RAM as they do on disk. You can get the RAM usage by:
width*height*4 (for images with an alpha channel)
and
width*height*3 (for images without an alpha channel)
An Android app is allotted a definite amount of heap space in the RAM, which will always be the same on a particular device and ROM version on that device. The minimum is 16 MB, though these days most devices give you a more comfortable 32 MB or 64 MB. It really depends on the device.
You get Out of Memory Exceptions (OOMs) when your app exceeds this heap space. The simple fix is: Don't exceed this heap space.
The best way to get quality images in your app is to use the density buckets and provide different sizes from which Android can choose. LDPI screens cannot make use of high res images anyways, so you should only supply a low res on in LDPI. On the other hand, HDPI devices can make use of better resolution, and if you supply one Android can use it. It is almost a given that the higher the resolution of the device, the more heap space you will be allotted for the running of your app.
Another way to manage memory is to only load what you need, by implementing lazy loading. This is especially helpful with listviews and scrollviews and other adapter based View systems.
On Android 3.0 and above, you can request a bigger heap by using android:largeHeap="true". However, this should be avoided as the user will notice other apps of theirs being removed from memory whenever your app is launched, and it is not guaranteed that you will receive a larger heap in any case.

OutOfMemory when allocating int array < free memory

In my android app I'm allocating a large int array. This sometimes gives me an OutOfMemory error, when I think there should be sufficient memory. This is an example of what I get:
// always this value
ActivityManager.some_instance.getMemoryClass() = 128 Mb
// always this value
Runtime.getRuntime().maxMemory()/(1024*1024) = 128 Mb
// example value
Runtime.getRuntime().freeMemory()/(1024*1024) = 81 Mb
// example value, can also be bigger than freeMemory()
arrayLengthToAllocate*4/(1024*1024) = 47 Mb
To be clear, I get the OutOfMemory error for situations where the last value is larger or smaller than freeMemory().
Why do I get the error? Is the heap size not increased when the allocation is performed? The memory use of the app just before trying to allocate is about 8 Mb, so that cannot be the problem.
PS. Other approaches than using an int[] of what this app is doing are not possible.
Generally speaking most devices have a cap on the amount of memory you can use. I know that originally this was set at 16MB per application. I think this has increased since, but it is still something you should be taking into account.
You also have to bare in mind that your applications footprint can fluctuate and that the Android Operating System has to give memory to other applications as well which are competing for resources. It may be that Android is identifying your application as being a resource hog and is cutting back it's resources.
Storing 47MB of integers in memory cannot be a very good use of an application's memory, is there no easier approach? I fail to see why you would need so many integers to be so readily available. Surely adding the integers to a SQLite database, reading them in as required, thus moving the bulk of the memory requirements away from RAM and onto physical memory would be a better approach?
When you are hitting OutOfMemory errors it is normally an indication that you are being a bit too greedy and the best way of limiting them is to scale back what you are doing, find a different approach.
The memory amount you get is the system memory size. Each application has a limited subset of that, which depends on a few system variables. In general it's something in the order of 16 - 32 MB, sometimes a bit bigger for tablets.
I figured out that the problem is heap fragmentation. Defragmentation has limits such that there are simply not enough free consecutive bytes in the heap to fit the single large array. I restructered the data into a two-dimensional array which solves the problem as each row has its own location in the heap. Downside is that retrieving the data from the array is slightly slower.

Why does Android allocate more memory than needed when loading images

Folks, I don't think that this is a duplicate and is NOT one of those how do I avoid OOMs questions. This is a genuine quest for knowledge so hold off on those down votes please...
Imagine I have a JPEG of 500x500 pixels. I load it as ARGB_8888 which is as "bad as it gets".
I would expect Android to allocate 500x500x4 bytes = a little under 1MB however, look at a heap dump and you will see that Android allocates significantly more, often factors of 5-10 times greater.
You frequently see questions on here about OOMS where the stack trace shows a heap request of say 15MB and it is Always much larger than is required simply to hold the bytes of the image. The OP usually catches some downvotes then is bombarded with stock answers and comments about using less memory (thanks Romain!) and in scaling. I think there is more than meets the eye here.
Anybody know why this is?
If there is no apparent answer, I will put together an SSCCE if it helps.
PS. I assume that JPEG vs PNG etc is irrelevant since we're talking about the memory usage of the backing bitmap which is simply x times y times BPP - or am I being slow?
It used to be quite a common trick with memory management to grab a pool or block of memory which is parceled out into smaller requests. When I worked with embedded systems it was a common practice to maintain pools of memory of different sizes, and we just allocated a block larger than the amount requested from a pool . It is a convenient way of preventing too much memory fragmentation. Maybe this is happening here.

Android heap size limit, do we still really need to design applications with a 16 MB limit in mind?

Like the title says, should I still be designing my application around a 16 MB heap size limit? The reason I ask is that I've been developing a game recently that runs fine on my nearly 2 year old Droid 2. But when I test my app using an AVD with a 16 MB heap size limit, I get out of memory errors. Monitoring my application with DDMS shows that the total memory allocated for my game is around 20 MB. It isn't a huge difference, but getting my game to work under that 16 MB limit would really hurt the visuals.
Now, if this was 2008, I wouldn't even be asking this question. But it's 2012, nearly 4 years after the G1 debuted. Is it safe to say that most phones made in the past year allow applications to allocate more than 16 MB of memory? Or am I really screwing myself by not designing my application with a 16 MB limit in mind?
The heap limit varies depending on the device resolution (and probably also other factors). So on a high resolution device the heap limit may be 30MB while on a low resolution G1 it is 16MB. Generally you should change your graphics accordingly so low resolution devices uses low resolution graphics (which takes up less space) and high resolution devices uses high resolution graphics (which takes up more space).
Yes we still need it but not in every case.
If you are using native code then memory allocated by c compiler does not include in this limit.So you can provide more memory to your application essential component.
and second way is to using Texture to draw images using OpenGL.then memory for these Texture does not include from limited memory.
But these technique can not be implement in every case
One more important thing , you can not use these 30 MB completely also.Only 30 % of it is usable for one application .

Categories

Resources