Note: This post is by your favorite programmer, Joraaver!

Hey guys. Sorry for the long wait. My first project in my Operating Systems class took an insane amount of time. But enough about me. Time to dissect the game (WARNING: LONG and MEATY)!

I'll break this post up into 4 parts (NOT 4 posts, 4 parts): setup, analysis, solution, and remarks. Please keep in mind that I strive to explain everything to my best understanding, but I'm a beginner game developer, a student, and above all, nowhere near perfect. If I did something wrong or could have done something better, PLEASE tell me!

The Setup

It was around 11:50 pm Saturday night, January 4th, when a play-tester called me to report an error. After the 16th level and the 20th level, he would get a java.lang.OutOfMemoryError: Direct buffer memory error. So, as any developer would, I collected the details of his machine--graphics card, RAM, operating system, the works. However, the machine wasn't anything special, so I will leave those details out. The main part occurs now: I have a bug, it's 12:10 am Sunday morning, and I want to release around 10:00 am Sunday morning. What do I do?

The Analysis

First, I needed some way of reproducing this error. No matter what, in jME, I couldn't recreate the error. I decided to build and play the game. No luck there either. Only when I played the test version we hosted for our play-testers did I get the error. This led me to suspect that the error had to have something to do with the difference in environments, perhaps the difference in the way memory was handled in the built version than the compiled version in NetBeans. After doing a little digging, a suggestion came by to run a scanner on the memory to see if memory leaks were occurring. It figures that in a language that's supposed to take care of memory so the developer doesn't have to, the game-breaking bug that occurs hours before release may involve just that.

Moving forward, I decided to start the game with the NetBeans Profiler. jME is built as a wrapper around NetBeans, so the NetBeans Profiler comes with it. I followed tutorial from NetBeans, found HERE to start the debugging.

After reading the tutorial, I first needed to see if some object's Surviving Generations was continuously increasing. If so, then I had a memory leak. It was time to fire up the profiler and get going.

The settings I used to start the profiling.

After one run, I only got 3-4 Surviving Generations. This didn't seem like too much. After another run, the number rose to 5 Surviving Generations. It was increasing, I wasn't sure why, and I wasn't sure if I should take it seriously or not, since the generations were so small. Even when I sorted the objects by Surviving Generations, as suggested by the tutorial, there were no glaring issues. Yes, the general Surviving Generations increased, but not due to anything I was allocating. Nonetheless, I started by removing my obsolete collections first. I had a bunch of Vectors that are obsolete collections in Java. Changing them to ArrayLists was pretty easy (in fact, all I had to do was change the name). I restarted the profiler, and the Surviving Generations increase still existed, but it was extremely slow. In fact, after running through the game 5 times, the Surviving Generations increased maybe one or so each time, but the funny thing was that the telemetry (pictured below) showed it never spent any time in garbage collection (GC). I could only assume that with only 5 Surviving Generations, the GC didn't even think it needed to do its job yet. This obviously wasn't my problem then, but this also left me stumped. Regardless, it was only 2:00 am, and I hadn't given up yet.

Telemetry of the profiler. From left to right: heap size analysis, GC analysis, and thread analysis.

After some searching, I realized that perhaps a memory leak wasn't the issue at all. Some jME specific forums popped up after entering a more 'jME' specific search (I don't know why I hadn't thought of this earlier). There were some terms being thrown around regarding the default heap size of the VM. So far in my career, the heap has been a more abstract, "out of the scope of this class" sort of concept, so I wasn't sure if I'd understand what I was about to fix. I'm still not sure, but I am about to do the best I can to explain.

According to the link on JVM Tuning there are three parameters I wanted to look at: Xms, Xmx, and Xmn.

Xms is the starting size of the heap



Xmx is the max size of the heap

