Monday, 29 November 2010

Getting FloatBuffer data: BufferUnderFlowException

When getting FloatBuffer data from a mesh, you must be sure to rewind your buffer before copying it if you already have before. I was iterating subsets of vertex data for the same mesh (I have "submeshes", which are equivalent to Wavefront .obj groups or objects) and trying to get the vertex data for each submesh for some processing, but the second iteration I was getting a BufferUnderFlowException.

It took me longer than it probably should have to realise I needed to "rewind" the buffer so I could copy the data again. To do this simply call FloatBuffer.position() with zero to set its internal position back to the start.

Of course if you need to be performant, you probably shouldn't be copying it twice anyway... :)

Thursday, 11 November 2010

Java.String memory leak

Or "How I just saved myself 3 meg of precious Android heap memory".

I always glazed over whenever I came across how Strings are implemented in higher level languages. The most important advice I ever came across concerning them was "use a library that does all that string stuff for you". Of course I can make reasonable assumptions about how Java does strings:

1. There's a char buffer somewhere in there storing sequences of raw characters
2. It probably does something clever with them along the lines of the same way I do textures

So what happened? A loader parses an entire object file into a string, then passes a tokenized element of that string into an object as the object's name. It all seemed fine till I ran the Eclipse Memory Analysis Tool, when I found at the top of my memory usage hitlist a bit more than 3 megabytes of char data. As in, a couple of raw char[]. Full of, guess what? My entire object file.

"What's happened here?", I thought, stroking my chin. A closer look at my object in the debugger (a Submesh) revealed that sure enough, its name (supposed to be something like "grp 1"), which is a String, has the entire object file in its buffer. The String object stores an offset and length into the character buffer. The garbage collector looks at the 3 meg buffer and says "well, this Submesh object here still has a reference to this sequence of data, so I can't delete it!".

The fix is trivial: construct a new string from the passed in string, which makes a new buffer and frees up the old one for the GC's unreferenced memory hit squad.

I thought I'd post this because without running the MAT I never would have known I was leaking 3 megs of memory. It's worth checking.