Recently I found myself trying to track down an issue with my project which involved significant pauses in the frame-rate, particularly when spawning new items in the scene such as space craft and windows. Originally I assumed that the garbage collector kept reclaiming my textures from the asset cache and they were being contantly reloaded.
After installing the Java Profiler what I found was that a pause would often occur while the GC was running so I did a bit of reading on garbage collection and solved the problem by specifying the Concurrent Collector on the command line and revamping my Xms and Xmx settings.
Anyway I found the reading to be quite interesting and likely useful for any jME developer so I figured I’d share.
By default the JavaVM dynamically selects a GC at startup depending upon the environment in which it is running, but it doesn’t really know the requirements of the application so if you don’t specify a collector on the command line you might find the way garbage collection effects your game’s performance varies from one environment to the next.
You may also want to consider getting to know the Xms and Xmx command line options. The Xms option specifies the minimum amount of memory to allocate for the heap while the Xmx option specifies the maximum. The JVM will initially allocate the full Xmx amount at startup, but only Xms will be available to your application and that amount will dynamically expand up to Xmx and contract back to Xms as your applications memory requirements change.
In respect to Xms and Xmx settings you may find that if your Xms setting is too low your game may stutter initially while the VM expands the heap size and setting it too high may cause longer GC runs because it ends up letting the memory fill with dead references and then clean them all up in one long run. Similarly setting your Xmx too low may result in too frequent GC runs or, obvioulsy, out of memory problems causing your application to crash. Of course setting your Xmx setting too high may rule out the usage of your game on systems with less memory.
It depends on what you mean, it will probably not request that much memory from the OS initially. It will request a percentage of that. The “commited” heap space (a metric you can see if you run jconsole) is the amount of memory it can use for heap allocation without requesting more memory from the OS. Many GC-algorithms will trigger when approaching commited heap, and if they are able to reclaim enough memory everything is good. If they are unable to stay safely below commited heap the JVM will ask the OS for more memory - up to Xmx amount of memory.
Yeah, it’s -Xms that controls how much the JVM will allocate immediately. It won’t have to go back to the OS for memory until it detects that it needs more than that. (“Need” being defined as usage + head space)
Also, for JME apps… make your direct heap super large and keep your regular -Xmx heap reasonable. Else GC will rarely happen and the direct heap will run out of space.
Direct memory is not factored into the JVM’s decision to GC. If you have -Xmx=512m then set direct heap to at least 1 gig.
Edit: note this is mostly true for apps that create meshes or dynamic textures. But note that lots of BitmapText variation can churn through direct buffers too.
Yeah, I suppose I wasn’t entirely clear on what they mean by “reserved.” The Oracle article says that Xmx amount is “reserved” at startup, but only Xms is available to the application at that time.
“A number of parameters affect generation size. The following diagram illustrates the difference between committed space and virtual space in the heap. At initialization of the virtual machine, the entire space for the heap is reserved. The size of the space reserved can be specified with the -Xmx option. If the value of the -Xms parameter is smaller than the value of the -Xmx parameter, not all of the space that is reserved is immediately committed to the virtual machine. The uncommitted space is labeled “virtual” in this figure. The different parts of the heap (permanent generation, tenured generation and young generation) can grow to the limit of the virtual space as needed”
I looked up direct memory allocation and came across an IBM article that indicated, for Java8, Java does not limit the size of direct memory. Is this something that’s new in Java 8 and older JVMs imposed a limit?
“…By default, the JVM does not set a limit on how much memory is reserved for Direct Byte Buffers. A soft limit of 64 MB is set, which the JVM automatically expands in 32 MB chunks, as required.”
My project uses Java 1.8.0 update 51 so I’m wondering if I need bother with the -XX:MaxDirectMemorySize option.