In a recent post I discussed a method we’re using for automatically setting the java heap size appropriately at runtime. It now turns out that the issue of setting the heap size is complicated by the fact that the heap size you request on the command line isn’t necessarily what you get given. In some cases the differences are modest, but sometimes they can be significant – amounting to hundreds of megabytes of discrepancy.
The simple test I did was to compare the heap size requested by setting the -Xmx value on the java command with the actual amount of available memory as reported by Runtime.getRuntime().maxMemory(). What I found was that the relationship between these two values isn’t 1:1, isn’t fixed at a given ratio, and is platform (and indeed VM) dependent.
According to this bug report the actual implementation of -Xmx is VM-dependent, so that the value you supply on the command line is merely a suggestion to the VM and it’s free to do whatever it likes. Because I’d like my software to work consistently on all platforms I therefore had a look at what the different VMs actually do.
The OSX VM actually stays very close to the requested amount of memory across the whole range of requested heap sizes. The linux and windows VMs though overcommit at small heap sizes (there seems to be a minimum allowed heap size of ~10MB), but undercommit by up to 12% at larger heap sizes. When you’re requesting a heap of serveral gigabytes in size a 12% loss is a significant amount of memory.
Our immediate solution to this problem is to do a trial run where we launch a small program which reports the actual heap size allocated. We then relaunch the normal java command, increasing the heap request size by a correction factor calculated from the trail run. This seems to produce consistent results on all platforms and gives us what we asked for in the first place.