To the downvoters: I'm not pasting any code since my question is generalized, I'll post some as soon as someone request it.
In my application I load a user's playlist in form of quite a large JSONArray on Activity's start, parse and display this data in a ListView. If the user presses the Update button the whole operation gets repeated, same objects get overwritten. I noticed that the RAM amount used by the app gets increased randomly between 0.4 and 1 MB with each update. I'm trying to figure out the reason, the same memory addresses just get overwritten with new data, why does the RAM consumption grow? I also tried to set all used objets to null before doing the update, this decreased the RAM amount used but only by about 100KB.
I have no explanation for that issue, since there're same variables which just get overwritten. The size of server response has not changed. Any ideas how to fix this memory leak?
Because the same memory addresses don't get overwritten. You're creating new objects that take up new memory, and both copies will stick around until the old one is garbage collected. You can speed that along by making sure there's no dangling references to the old data anywhere in the app (by explicitly setting them to null), or by calling System.gc (although that has large negative penalties to it). But growing in that situation is expected. What shouldn't be happening is that if you do an hprof after getting the result several times you should never see the total number of instances of your array increasing unbounded. If you do, then you need to track up the chain of owners and see who's still hanging on.
Related
I have been coding this application that shows images of bus lines schedules. There are currently 32 lines and each of them has it's own image (can't use text due to the formatting and lack of data, had to do a compromise). I made it fetch an echo from a PHP file on my server and it retrieves data regarding bus lines and their images, then it downloads that data and images to the internal storage and loads the buttons for each line (dynamic layout).
ImageViews are set to null when they are created and they are only populated once you click on the button. I have noticed that my app uses around 20MB of RAM just as it starts. Opening 10-15 lines (10-15 images are loaded into ImageViews), RAM usage climbs up to 60MB and then it crashes (reaches my device's heap size limit). I know that image intensive applications tend to use a lot of RAM and my plan is to limit it to only one image per time (so once the user clicks on some other bus line, the others are closed and their imageviews are set back to null), but what is wondering me, can empty ImageViews cause RAM to be around 20MBs? My images are 320px in width and ranging from 200 to 1500px in height (I know, it's a lot), but I have set them to grayscale and compressed them (Size of the images is from 50kb up to 150kb).
My application's APK is 710kb in size, app when installed is around 3MB and with data it totals to 7.5MB.
So, to clarify, my questions are:
*1) Can empty ImageViews cause high RAM usage as well?
2) If yes, should I dynamically create an ImageView and populate it once the user clicks on the button, instead of the current approach when they are all created at startup?
3) Can multidimensional variables (mostly strings, 6 strings with 35 dimensions) cause high RAM usage as well? Most of them are around 10 characters long.
4) Are there any tools which I could use on Android Studio which could help me to locate possible memory leaks?
5) Do non-global variables get automatically destroyed once the ie. function has returned a value or do I need to manually set them to null after I'm done with them?
6) What are generally some good practices to reduce RAM usage on Android when developing an app?*
Sorry for not being very technical here, I'm not a professional programmer or anything, this is more of a hobby of mine and I'm trying to learn a bit more here. Thank you for reading.
Image that shows what my app does:
All bus lines are collapsed
Once you click on the button, it shows the bus schedule for that line
*1) Can empty ImageViews cause high RAM usage as well?
Probably not. It's the bitmaps themselves that take a lot of space, not the ImageViews. Keep in mind that in-memory bitmaps won't be compressed, so it's not the file size that you need to take into account but the number of pixels.
3) Can multidimensional variables (mostly strings, 6 strings with 35
dimensions) cause high RAM usage as well? Most of them are around 10
characters long.
Probably not.
4) Are there any tools which I could use on Android Studio which could
help me to locate possible memory leaks?
You should use the Android Debug Monitor (Tools menu > Android > Monitor (DDMS included). It has a memory heap viewer that will show you what the big offenders are. It can take heap dumps in HPROF format that you can also analyze with other Java heap viewing tools.
5) Do non-global variables get automatically destroyed once the ie.
function has returned a value or do I need to manually set them to
null after I'm done with them?
Unless you're doing something strange, the memory used by local variables is eligible for garbage collection once those variables pass out of scope, so to answer your question, you don't need to set them to null.
In my case, I only put the 1 image to drawable so the RAM of application increase a lot.
Then, I put image to each drawable-...pdi files, the RAM size decrease
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.
I need to search through text files (around 40MB) in my app with regular expressions, as you can imagine, it normally takes 1 minute or so to get it done. AND I have to do it repeatedly.
I wonder if I can keep these files in RAM after the first search. Can I possibly do that? I mean, find a way to explicitly say keep something in RAM for some time.
Consider putting your search results in a WeakHashMap, with keys that only exist for the duration that you need the values to exist, like the scope of an Activity. Watch out for memory issues though. On some devices, your application's process may only have a heap size as low as 16M.
Keep the results in a custom object that will save the search result. This will keep it in RAM (as long as you keep a reference to it).
Also keep in mind that allocating 40 MiB in RAM in Android devices is not a very good idea since RAM is quite limited in a lot of low-end devices. This can make your application a very tasty target for Android when it looks to free memory.
I have an app that downloads a csv file online then saves it locally so the app will work even if it is offline. My problem is when the user closes the app then opens it again immediately, the app hangs while parsing the saved csv file and throws OutOfMemoryError. However, I noticed that when I open the app again after a few minutes it works just fine.
The downloading, parsing and saving are done on separate threads.
What can be the solution to this?
One possibility: out-of-memory errors can have more to do with an overworked GC than with an actual shortage of memory. If you allocate large pieces of memory, then free them, then allocate even larger pieces, you get to a point where you have a lot of large bits of free memory taking up space but unusable because they're not large enough. The GC is frantically trying to move things around and merge these pieces into one contiguous block for the next allocation, but rather than look bad because it's taking too long, it will just throw an OutOfMemory exception, even though 90% of memory is theoretically available (and will be available if you can give it a minute).
In your case, I'd suspect ArrayList. It keeps an array of references. As you add entries, it adds to the array. When it runs off the end, it allocates a new, bigger, one and frees the old one. These discards pile up if you keep it busy. Hashtables have similar problems. LinkedList and TreeMap don't, because they work with small bits of memory.
I don't know too much about Android, but I'm guessing the app doesn't really close when you close it briefly, so when you restart it it's the same free-memory-fragmented execution as before. If you wait a while it may be a new execution. Even if it's not, the GC has had time to clean things up and you're fine.
The solution you want is probably to force a garbage collection (System.gc()) each time you "start up" your system. It gives the GC a chance to put everything in order before allocating space for you, and it won't take long. In a sense, you're giving the GC permission to lock up your program for half a second, which it would not do on its own. (And if it did, it would pick an awkward time to do it--while the user's entering text, say.)
Avoiding large arrays by using linked collections is another solution, but arrays are fast and when you can spare a half-second of the user's time there's no reason to switch.
Hope this helps. If it's not the problem this time, maybe it will be next time.
Addition: Unfortunately, System.gc() is just a "suggestion". It may not be doing the job we hoped it would do. Or you may be getting into trouble after the call. The other big fix I should have mentioned before would be to set the initial size on ArrayList very large, if that is what your are using. Making it two or three times the size it needs to be will probably save you ten times that amount of memory over a run--and save time, too. This works for any array-based structure (hash tables and plain arrays). Beyond that, pointer-based structures like LinkedList will not have this problem if you can get around their disadvantages.
I can't seem to find any information to help me understand the memory readings from meinfo. My application loads a bunch of images, uses them, and then when the view is switched it should get rid of them and get some new images.
The meminfo output shows the native size as increasing as my application goes on. Allocated goes up and down (although very little) throughout and free remains faitly low.
THe app starts at about 10k native size and by the time it reaches the finish it's 31k. Does this indicate a potential memory leak or is this related to some form of caching?
I recycle my bitmaps after I finish with them and I null the views that hold them when finished with them. I can't understand where (if at all) I may be going wrong.
Can anyone offer advice on the meaning (and my interpretation) of this information?
Thanks