If I had a memory leak, wouldn't I always get an OutOfMemoryError eventually? As I wrote on the first post, the JVM is never throwing one.
That is true, but continual full GCs means that the app's working set size is a very large percentage of the heap and that you have sized the heap too small. And when you use the CMS collector you need to size the heap even larger, if you don't then you run into the possibility of the CMS collector not being able to free up memory in a timely fashion, in which case a very expensive (time-wise) stop-the-world collection takes place. Right-sizing the heap usually takes a lot of GC monitoring and experimentation to get right, though the easiest way is to allocate a very large heap to begin with (like Jimy Liu suggested) and monitor that, then you can usually come up with a decent heap size.