If you use the runtime/totalMemory solution that has been posted in many answers here (I've done that a lot), be sure to force two garbage collections first if you want fairly accurate/consistent results.
For effiency Java usually allows garbage to fill up all of memory before forcing a GC, and even then it's not usually a complete GC, so your results for runtime.freeMemory() always be somewhere between the "real" amount of free memory and 0.
The first GC doesn't get everything, it gets most of it.
The upswing is that if you just do the freeMemory() call you will get a number that is absolutely useless and varies widely, but if do 2 gc's first it is a very reliable gauge. It also makes the routine MUCH slower (seconds, possibly).