title: Avoid memory fragmentation when allocating lots of arrays in Java
body: <p>I am developing an application in Java that runs on Windows Mobile devices.  In order to achieve this we have been using the Esmertec JBed JVM, which is not perfect but we are stuck with it for now.  Recently we have been getting complaints from customers about OutOfMemoryErrors.  After a lot of playing around with things I discovered that the device has plenty of free memory (approx. 4MB).</p>
  
  <p>The OutOfMemoryErrors always occur at the same point in the code and that is when expanding a StringBuffer in order to append some characters to it.  After adding some logging around this area I found that my StringBuffer had about 290000 characters in it with a capacity of about 290500.  The expansion strategy of the internal character array is simply to double the size, so it would be attempting to allocate an array of about 580000 characters.  I printed out the memory usage around this time too and found that it was using about 3.8MB of about 6.8MB total (although I have seen the total available memory rise to around 12MB at times, so there is plenty of room for expansion).  So it is at this point that the application reports an OutOfMemoryError, which doesn't make much sense given how much there is still free.</p>
  
  <p>I started thinking about the operation of the application up to this point.  Basically what is happening is I am parsing an XML file using MinML (a small XML Sax Parser).  One of the fields in the XML has about 300k characters in it.  The parser streams the data from disk and by default it loads only 256 characters at a time.  So when it reaches the field in question the parser will call the 'characters()' method of the handler over 1000 times.  Each time it will create a new char[] holding 256 characters.  The handler simply appends these characters to a StringBuffer.  The default initial size of the StringBuffer is only 12, so as the characters are appended to the buffer it is going to have to grow a number of times (each time creating a new char[]).</p>
  
  <p>My assumption from this was that it is possible that while there is enough free memory since the previous char[]s can be garbage collected, maybe there is no contiguous memory block big enough to fit the new array I am trying to allocate.  And maybe the JVM is not smart enough to expand the heap size because it is stupid and thinks there is no need because apparently there is enough free memory.</p>
  
  <p>So my question is: does anyone have any experience of this JVM and might be able to conclusively confirm or disprove my assumptions about memory allocation?  And also, does anyone have any ideas (assuming my assumptions are correct) about how to imrove the allocation of the arrays so that the memory won't become fragmented?</p>
  
  <p>Note: things I've tried already:</p>
  
  <ul>
  <li>I increased the initial array size of the StringBuffer and I increaed the read size of the parser so that it wouldn't need to create so many arrays.</li>
  <li>I changed the expansion strategy of the StringBuffer so that once it reached a certain size threshold it would only expand by 25% rather than 100%.</li>
  </ul>
  
  <p>Doing both of these things helped a little, but as I increase the size of the xml data going in I still get OutOfMemoryErrors at a fairly low size (approx. 350kb).</p>
  
  <p>Another thing to add:  all of this testing was performed on a device using the JVM in question.  If I run the same code on the desktop using the Java SE 1.2 JVM I don't have any problems, or at least I don't get the problem until my data reaches about 4MB in size.</p>
  
  <p>EDIT:</p>
  
  <p>another thing I have just tried which has helped a bit is I set the Xms to 10M.  So this gets past the problem of the JVM not expanding the heap when it should and allows me to process more data before the error occurs.</p>