Is the LruCache constrained by the Android app memory space? - android

I'm looking at the docs and trying to understand if the LruCache is competing for heap resources with the rest of my app or if it's actually using some sort of elaborate disk swapping mechanism.
The reason I'm asking is that I want to allocate a lot of memory for the cache (say a gig) so that if the device loses its Internet connectivity a large amount of image data can persis locally. However, if the LruCache is constrained by the size of the App's heap memory allotment this obviously won't work.
I'm hoping someone can point me to more detailed documentation about how this feature works and if this *isn't the right feature to handle this need, if I need to roll my own or if there's an Android native disk swap memory class that I'm overlooking that maybe should be combined with LruCache (or used entirely on its own?)

I'm looking at the docs and trying to understand if the LruCache is competing for heap resources with the rest of my app or if it's actually using some sort of elaborate disk swapping mechanism.
It is using heap space of your app. You can see the LRUCache source code to confirm this.
However, if the LruCache is constrained by the size of the App's heap memory allotment this obviously won't work.
Correct.
if I need to roll my own or if there's an Android native disk swap memory class that I'm overlooking
There is really no concept of "disk swap memory" at the Android app level, and very few devices even implement it at the OS level.

Related

What are advantages of setting largeHeap to true?

I have an application with large number of classes & also many libraries are included, I am setting android:largeHeap="true" as i am getting memory issue, My Manifest file code is attached.
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="My Huge Application"
android:largeHeap="true"
android:logo="#drawable/logo"
android:screenOrientation="portrait"
android:theme="#style/AppTheme" >
</application>
I had to ask that is this a good practice?
Kindly suggest advantages and disadvantages (pros and cons) of using it.
Way too late for the party here, but i will offer my 0.02$ anyways.
It's not a good idea to use android:largeHeap="true" here's the extract from google that explains it,
However, 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. 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.
here's the complete link of the documentation
https://developer.android.com/training/articles/memory.html
UPDATE
After working excrutiatingly with out of memory errors i would say adding this to the manifest to avoid the oom issue is not a sin, also like #Milad points out below it does not affect the normal working of the app
UPDATE 2
Here are a few tips to deal with out of memory errors
1) Use these callback that android gives onLowMemory, onTrimMemory(int) and clear the cache of image like (picasso, glide, fresco....) you can read more about them here and here
2) compress your files(images, pdf)
3) read about how to handle bitmap more efficiently here
4) Use lint regularly before production pushes to ensure code is sleek and
not bulky
I think this is a very effective question, and let me add some details about advantages and disadvantages of using this option.
What You Get :
Obviously, you get larger heap, which means decreasing risk of OutOfMemoryError.
What You Lose :
You may lose some frames, which can cause a visible hitching. Larger heap makes garbage collections take longer. Because the garbage collector basically has to traverse your entire live set of objects. Usually, garbage collection pause time is about 5ms, and you may think few milliseconds are not a big deal. But every millisecond count. Android device has to update its screen in every 16 ms and longer GC time might push your frame processing time over the 16 millisecond barrier, which can cause a visible hitching.
Also switching apps will become slower. Android system may kill processes in the LRU cache beginning with the process least recently used, but also giving some consideration toward which processes are most memory intensive. So if you use larger heap, your process would more likely to be killed when it's backgrounded, which means it may take longer time when users want to switch from other apps to yours. Also other backgrounded processes will more likely to be kicked out when your process is foreground, because your app require larger memory. It means switching from your app to other apps also takes longer.
Conclusion :
Avoid using largeHeap option as much as possible. It may cost you hard-to-notice performance drop and bad user experience.
If you must use (and retain) a large amount of memory, then yes, you can and should use android:largeHeap="true". But if you do use it, you should be prepared to have your app flushed from memory whenever other apps are in the foreground.
By "be prepared," I mean that you should design for that likelihood, so that your onStop() and onResume() methods are written as efficiently as possible, while ensuring that all pertinent state is saved and restored in a manner that presents a seamless appearance to the user.
There are three methods that relate to this parameter: maxMemory(), getMemoryClass(), and getLargeMemoryClass().
For most devices, maxMemory() will represent a similar value to getMemoryClass() by default, although the latter is expressed in megabytes, while the former is expressed in bytes.
When you use the largeHeap parameter, maxMemory() will be increased to a device-specific higher level, while getMemoryClass() will remain the same.
getMemoryClass() does not constrain your heap size, but it tells you the amount of heap you should use if you want your app to function comfortably and compatibly within the limits of the particular device on which you are running.
maxMemory(), by contrast, does constrain your heap size, and so you do gain access to additional heap through increasing its value, and largeHeap does increase that value. However, the increased amount of heap is still limited, and that limit will be device-specific, which means that the amount of heap available to your app will vary, depending on the resources of the device on which your app is running. So, using largeHeap is not an invitation for your app to abandon all caution and oink its way through the all-you-can-eat buffet.
Your app can discover exactly how much memory would be made available on a particular device through using the largeHeap parameter by invoking the method getLargeMemoryClass(). The value returned is in megabytes.
This earlier post includes a discussion of the largeHeap parameter, as well as a number of examples of what amounts of heap are made available with and without its usage, on several specific Android devices:
Detect application heap size in Android
I have not deployed any of my own apps with this parameter set to true. However, I have some memory-intensive code in one of my apps for compiling a set of optimization-related parameters, that runs only during development. I add the largeHeap parameter only during development, in order to avoid out of memory errors while running this code. But I remove the parameter (and the code) prior to deploying the app.
Actually android:largeHeap is the instrument for increasing your allocated memory to app.
There is no clear definition of the need to use this flag. If you need more memory - Android provides you with a tool to increase it. But necessity of using, you define yourself.
I have an App with almost 50 classes
I don't think this makes much problem. The reason why you've got outOfMemory error is usually loading too much images in your app or something like that. If you are unhappy to use large heap you must find a way to optimize using memory.
You can also use Image Loading Libraries such as Picasso, UIL or Glide. All of them have the feature of image caching in memory and/or on disk.
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.

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.

Is there a way to compact memory in android to lower the high water mark?

Please note I do NOT have a memory leak. My question is about a subtler issue.
I recently wrote an android app which does image processing. The image is loaded as a Bitmap, then copied out in pixels, processed in a way that uses lots of memory (think Fourier transforms in floating point representations and stuff), then converted back into a bitmap and saved.
The problem is, through at least android OS 2.3, the total memory limitation (typically 16MB) is combined java and (externally stored) Bitmaps, and the java high water mark doesn't go down (that I can discern) even when the memory is free (successfully GC'd), which means when I go to allocate the final Bitmap, I am often "out of memory" even though by that point I have freed (and GC'd) most of the space. I.e., I never need the full 16MB at once, but the space left for Bitmaps appears to be 16MB minus the MAX historical java heap usage (as opposed to current usage).
I watched a tech talk by one of the android developers about memory issues and he implied this problem has been fixed in subsequent versions of the OS (they moved Bitmap memory into the java heap space), but in the meantime most of the people wanting to use my app are running 2.2 or 2.3.
Long story short, I am wondering if the java heap is ever compacted (de-fragmented, in effect) so that the high-water mark shrinks (and if so, how to make it happen)?
If not, then does anybody have another suggestion how to deal with this problem?
Long story short, I am wondering if the java heap is ever compacted (de-fragmented, in effect) so that the high-water mark shrinks (and if so, how to make it happen)?
Whatever its behavior is, it most certainly is not under your control.
If not, then does anybody have another suggestion how to deal with this problem?
Ideally, reuse your own Bitmaps. You don't indicate what "processed in a way that uses lots of memory" really is. However, if it does not change the dimensions or bit depth of the image, copy the data back out to the original Bitmap rather than allocating a fresh one, if you can.
Image processing on Android 2.x is one of the few places where I can see justifying using multiple processes. You will add overhead for schlepping the image data between processes, but the other process has its own heap (Java and native), so this may give you more "elbow room".
So far, no indication that there is any way to compact the memory.
Here is my workaround, which is suboptimal but much better than the behavior before:
I now intentionally hold on to the original Bitmap while I am doing my processing, and then recycle() and null it, and GC(), but not until just before allocating my output Bitmap.
What this does is reserve external (Bitmap) space, and cause my application to run out of java heap (during processing, before calling recycle()), which I can at least catch and handle by retrying on a smaller image. (Before, everything seemed to be fine until I tried to save, but by then it was too late and with no way to recover.)
Technically this limits my max image size to less than I should be able to do with the allotted memory (because I need to reserve space in the heap and external at the same time when in truth I never need both together), but at least I can still handle a reasonable image size.
What was happening before is I would free and recycle the Bitmap early which allowed the high water mark on the java heap to use up essentially all of my memory allotment, meaning from that point forward I couldn't open or create any more Bitmaps at all (other than tiny thumbnail sizes sometimes).
Imo, this is a major bug in the way android handles Bitmap memory, but I believe it is fixed in newer versions of the OS so hopefully I can disable this workaround conditional on the OS release.
I'm assuming that you already call Bitmap.recycle() but it's the only thing I remembered and you didn't talk about.

Is using largeheap in Android manifest a good practice?

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.

Categories

Resources