Skip to content

JVM Tuning in Martini

Martini Server Runtime is configured to run using Apache Tomcat, a Java Servlet Container. Tomcat, in turn, runs on top of a Java Virtual Machine (JVM).

While a generic JVM configuration may be suitable, it's recommended to tailor your JVM settings based on your organization's usage of Martini Server Runtime. This guide will discuss the various JVM configuration options that can help, directly or indirectly, to improve Martini Server Runtime's performance.

Tuning the JVM requires a thorough understanding of Java and JVM memory management. The individual responsible for JVM tuning should possess expertise in the production environment and JVM internals. Attempting to tune without this knowledge can have adverse effects on performance.

Understanding JVM Garbage Collection and Heap

The JVM utilizes a memory management tool known as the garbage collector (GC), which frees up unused Java objects in the heap. The heap is divided into two crucial parts: the young generation and the old generation.

The young generation is where new objects are allocated and aged. When it fills up, a minor garbage collection occurs. Objects with longer lifespans move to the old generation, triggering major garbage collection eventually.

Two key factors influencing garbage collection performance are:

  • Total available memory: Increasing memory allocation can reduce frequency of collections but may lead to longer pauses.
  • Proportion of heap dedicated to young generation: A larger young generation reduces minor collections but may increase major collections' frequency.

Setting JAVA_OPTS

You can set JAVA_OPTS in several ways depending on your environment:

  1. Adding to toro-martini (permanent for an application)

    a. Open <martini-home>/bin/toro-martini:

    1
    sudo nano toro-martini
    

    b. Add a new line or edit existing JAVA_OPTS for example:

    1
    JAVA_OPTS="-Xms2g -Xmx4g -Xmn1g"
    

    c. Save and Run Martini Server Runtime

    1
    sudo ./toro-martini debug
    
  2. In the shell (temporary for the session)

1
export JAVA_OPTS="-Xms2g -Xmx4g -Xmn1g" && sudo ./toro-martini debug

JVM Tuning Parameters

  1. Heap Size Settings: The Java Virtual Machine (JVM) has two main memory regions for managing heap: the young generation (for short-lived objects) and the old generation (for long-lived objects). You can tune the heap size with the following parameters:

    • Initial Heap Size (-Xms): Specifies the initial size of the heap. It is the amount of memory allocated to the heap at the start of the program.

      1
      -Xms2g  # Set initial heap size to 2GB
      
    • Maximum Heap Size (-Xmx): Specifies the maximum size the heap can grow to.

      1
      -Xmx4g  # Set maximum heap size to 4GB
      
    • Young Generation Size (-Xmn): Specifies the size of the young generation. This is a portion of the heap reserved for objects that are likely to be short-lived.

      1
      -Xmn1g  # Set young generation size to 1GB
      
    • Example:

      1
      JAVA_OPTS="-Xms2g -Xmx4g -Xmn1g"
      
  2. Garbage Collection (GC) Tuning: Garbage collection is a critical factor in JVM performance. You can control the GC behavior using various flags:

    • Use Parallel GC (-XX:+UseParallelGC): This is a multi-threaded garbage collector that can help improve throughput for applications with a large heap.

      1
      JAVA_OPTS="-XX:+UseParallelGC"
      
    • Use G1 Garbage Collector (-XX:+UseG1GC): The G1 collector is designed to provide predictable pause times and is suitable for large heap sizes.

      1
      JAVA_OPTS="-XX:+UseG1GC"
      
    • Use CMS Garbage Collector (-XX:+UseConcMarkSweepGC): CMS is designed to minimize pause times.

      1
      JAVA_OPTS="-XX:+UseConcMarkSweepGC"
      
    • GC Logging: Enable GC logs for detailed insights into garbage collection performance.

      1
      JAVA_OPTS="-Xlog:gc*"
      
    • Example:

      1
      JAVA_OPTS="-XX:+UseG1GC -Xlog:gc*"
      
  3. Thread Stack Size: The thread stack size can be adjusted to allocate more or less memory for each thread. This is useful for applications that create many threads.

    • Thread Stack Size (-Xss): Sets the stack size for each thread.

      1
      JAVA_OPTS="-Xss1m"  # Set stack size to 1MB per thread
      
  4. JVM Garbage Collector Threads: You can tune the number of threads the garbage collector uses:

    • Parallel GC Threads (-XX:ParallelGCThreads): Sets the number of threads used during parallel garbage collection.

      1
      JAVA_OPTS="-XX:ParallelGCThreads=4"  # Use 4 threads for parallel GC
      
    • G1 GC Threads (-XX:ConcGCThreads): Sets the number of threads used by G1 GC.

      1
      JAVA_OPTS="-XX:ConcGCThreads=2"  # Use 2 threads for G1 GC
      
  5. JVM Performance Flags: There are several flags for improving JVM performance or enabling advanced features.

    • Enable Optimizations (-XX:+UseCompressedOops): Use compressed object pointers for 64-bit JVMs to save memory.

      1
      JAVA_OPTS="-XX:+UseCompressedOops"
      
    • Tiered Compilation (-XX:+TieredCompilation): This enables tiered compilation, which can improve startup time and overall performance.

      1
      JAVA_OPTS="-XX:+TieredCompilation"
    • JVM Debugging (-Xdebug, -Xrunjdwp): For debugging purposes, you can pass options to enable remote debugging.

      1
      JAVA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
      
  6. JVM Miscellaneous Options:

    • Disable JIT Compiler (-Djava.compiler=none): This disables the Just-In-Time compiler and can be useful for debugging.

      1
      JAVA_OPTS="-Djava.compiler=none"
      
    • Set System Properties (-Dproperty=value): Set custom properties that the Java application can access via System.getProperty().

      1
      JAVA_OPTS="-DmyProperty=value"
      
  7. Class Data Sharing:

    • Enable Class Data Sharing (-Xshare:on): Helps reduce startup time by sharing common class metadata across multiple Java processes.

      1
      JAVA_OPTS="-Xshare:on"
      
  8. JVM Heap Dump on OutOfMemoryError: If you want the JVM to generate a heap dump when it runs out of memory, use the following option:

1
JAVA_OPTS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump"

Testing

  1. Determine production environment requirements.
  2. Select suitable garbage collector.
  3. Configure garbage collector.
  4. Enable garbage collector logging. This can be as simple as using the JVM option:

    1
    JAVA_OPTS="-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintGCTimeStamps -Xloggc:gclog.log"
    
  5. Conduct tests mimicking real-world scenarios.

  6. Analyse garbage collection logs.
  7. Iterate based on results.

Example:

A test case comparing JVM arguments -Xms1g -Xmx1g and -Xms2g -xmx2g demonstrates minimal difference. Real-world scenarios may have varying outcomes.

Additional Resources

Refer to these links for further JVM optimization: