I think you have chosen the wrong garbage collection algorithm. The Java 8 documentation offers this guidance:
Selecting a Collector
Unless your application has rather strict pause time requirements,
first run your application and allow the VM to select a collector. If
necessary, adjust the heap size to improve performance. If the
performance still does not meet your goals, then use the following
guidelines as a starting point for selecting a collector.
If the application has a small data set (up to approximately 100 MB), then select the serial collector with the option -XX:+UseSerialGC
.
If the application will be run on a single processor and there are no pause time requirements, then let the VM select the collector, or
select the serial collector with the option -XX:+UseSerialGC
.
If (a) peak application performance is the first priority and (b) there are no pause time requirements or pauses of 1 second or longer
are acceptable, then let the VM select the collector, or select the
parallel collector with -XX:+UseParallelGC
.
If response time is more important than overall throughput and garbage collection pauses must be kept shorter than approximately 1
second, then select the concurrent collector with
-XX:+UseConcMarkSweepGC
or -XX:+UseG1GC
.
Source: Selecting a Collector
Based on your comments, it seems that your goal is to get peak performance; i.e. minimize the overall time spent on GC and related overheads.
That means that your best options are:
- Set some performance goals and let the JVM to decide which collector is best. See the Behavior-based Tuning material for details of the performance goals mechanisms.
- Select the Serial GC if you have only one core.
- Select the Parallel GC if you have more than one core.
If you want a one-size-fits all script that works irrespective of your hardware, the performance goal approach is best, though that means you won't be able to use platform-specific settings to (potentially) improve on the JVM's decisions.