First check on memory leak front with JStacks/JMaps, thread dumps and Memory analyser tools. If you don't have any leaks in memory of your system, you have to fine tune garbage collector algorithms.
Java offers different types of garbage collectors.
Have a look at strengths & weakness of various GC algorithms
The Serial Collector: The serial collector is the simplest one, and the one you probably won’t be using, as it’s mainly designed for single-threaded environments.
The Parallel / Throughput collector: Its biggest advantage is that is uses multiple threads to scan through and compact the heap. The downside to the parallel collector is that it will stop application threads when performing either a minor or full GC collection.
The CMS Collector: This algorithm uses multiple threads (“concurrent”) to scan through the heap (“mark”) for unused objects that can be recycled (“sweep”). It will be efficient if you either increase the size of the old generation (or the entire heap for that matter) or allocate more background threads to the collector.It uses more CPU in order to provide the application with higher levels of continuous throughput.
The G1 Collector: The Garbage first collector (G1) introduced in JDK 7 update 4 was designed to better support heaps larger than 4GB. The G1 collector utilizes multiple background threads to scan through the heap that it divides into regions, spanning from 1MB to 32MB (depending on the size of your heap). using the –XX:+UseG1GC flag.
If you are using G1 collector, you have to fine tune region size parameter. If 15 GB is your heap size, your region size should be (15 GB / 2048 ) MB, which is around 7 MB. Do not experiment more on New Gen Size. You can stick to default settings since this algorithm provides best performance with default values.
Have a look at this article:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html