I've recently run into a rash of users reporting Out-Of-Memory issues on my app. I've got the issue fixed for now, but there are still a few people that email me every now and again that say the app has crashed during a data load, so I'd like to get this figured out.
I've read everything I could find on memory management in Java (that's pretty much a near-oxymoron, right?) and memory profiling for Java and Android. Using the DDMS to watch the heap size as my app crunches through data loads, it was going as high as 7MB+, with allocated around 3MB, so I could see that somewhere I was using a lot of temporary objects that were later freed. All of my network data loads were using BufferedReaders, concatenating the reads into a single string for processing. So, I rewrote all of my network data loads as InputStreams that I was calling "read" on and reading blocks of 1k into a byte array, then concatenating that read into a String. This got the heap size down to a max of 4MB. This seemed to resolve the Out-Of-Memory issues for I'd say 99% of my users.
I then realized that concatenating the data into a String was actually a big waste as well (I'm probably the only person that didn't know about StringBuilder), so I changed all of my data reads again, back to BufferedReaders that appended the read data to a StringBuilder object. However, this didn't seem to improve the heap size at all, it's still at nearly exactly 4MB.
Sorry for the lengthy post, but here's my two questions: 1) What kind of heap sizes are other people seeing with their apps and aren't apps supposed to get 16MB of heap space to work with? Why would I be getting all of these Out-Of-Memory issues when my heap size gets to 7MB? 2) What is the most efficient way to read network data, is it what I've settled on now, BufferedReader with the read String being appended to a StringBuilder? I'm trying to get away from any temporary objects that I can, to keep the heap size down.