Child pages
  • Tuning the JVM
Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 18 Next »

Pre-requisites

Before conducting your tuning exercise:

  1. Define performance targets.
  2. Determine which version of the java JVM is available. More recent JVMs usually contain performance improvements of their own, especially in the area of garbage collection.
  3. Selection of a 64-bit JVM supports much more available memory.
  4. Select a garbage collector according to your needs and limitations. Bear in mind that garbage collectors have differing algorithms to suit particular goals and reduce the need to "stop the world". What is right for one implementation may not be right for another. You should test and compare with realistic scenarios and load in a pre-production environment.
  5. In tuning, start with the defaults and monitor the execution using jconsole and GC logs. Examine memory consumption and GC collection time and frequenscy and tune accordingly.

Caveat: These are recommendations only and it is recommended that customers refer to Oracle and other tuning documentation, and use a performance testing optimisation strategy to optimally configure IG according to deployment. Only an incremental optimisation strategy will determine the optimal configuration for a given deployment and user load.

Memory

As a proxy, IG is generally a low memory consumer, proxying request and response data between the client and server. Other factors to consider though in determining memory sizes are:

  • Caching (notification, session and request): size and lifetime
  • Resource size: as larger resources 

Heap Memory

  • IG largely consumes YoungGen space so JVM memory settings should be focussed there.
  • IG is a low user of OldGen memory, which remains largely static after startup, with a couple of exceptions to note:
    • if IG is proxying large resources then you may see more consumption here - as larger objects may be stored directly in OldGen memory.
    • Caching may increase the lifetime of objects, so obviating the the need for larger available OldGen space.

Metaspace Memory

  • Metaspace is the location where he JVM stores application metadata and is unlimited by default.

  • It is important to note that if not sized appropriately then if the JVM resizes Metaspace, a full GC must be done, which is expensive.


    GSA: I don't expect this kind of memory to need a lot of tuning, maybe just remove that section ?

    WM: Ok, but if Metaspace is resized (too small) then we require a time-consuming full-GC. I think it's not that well-known so we should mention it. I'll reduce it, to reduce its importance but keep the section with that detail in it.


    (Will remove Tuesday 30/6/2020 if no further comment)

Memory Options

While configuring memory is a trial and error process, and best optimised incrementally, the following memory options are worth considering:

OptionDescription
-serverEnsures the JVM uses server-optimised configuration, compilation and execution. This is the default with a 64-bit JVM.

-XX:InitialHeapSize<size>G

-XX:MaximumHeapSize=<size>G

Configure the initial and maximum heap space:

  • Equivalent to -Xms and -Xmx flags respectively.
  • Oracle recommend that these figures are set the same to avoid expensive allocation operations. However, recent improvements in G1GC with its adaptive optimization algorithm (see below) means that this may limit vertical scaling. Though it is still recommended to follow this practice, if using G1GC, consider testing individual initial and maximum values too.
  • As a start point, IG has been shown to operate well in performance testing with a heap size of 5Gb. That is, with this sized heap, even with more memory available, a memory increment was never done.

-XX:NewSize=<size>G

-XX:MaxNewSize=<size>G

Configure the initial and maximum YoungGen space:

  • This configuration is important to IG as a large consumer of Eden space.
  • Incrementally test to optimise, with anticipated concurrent load in a pre-production environment. The maximum should be within the overall allocated maximum heap-size (-Xmx), leaving space for non-heap memory.
  • If using G1GC, it is advised not to set these values and instead allow G1GC to optimise based on use. As ever, this should be tested.

-XX:+UseStringDeduplication

-XX:UseStringDeduplicationAgeThreshold=<N>

Prevent String duplication and so conserve memory (java 8u20+), reducing GC needs. The threshold can be provided to specify the age after which a String becomes a candidate for deduplication.

GSA: why not, but do we think that this can have a notable impact on our performances ?

WM: It's documented everywhere as advisable. It's also advised in the DJ tuning guide for 7.0. It's basically the inlining of Strings, as used to be the case pre-java8.

(Will remove Tuesday 30/6/2020 if no further comment)

-XX:MaxTenuringThreshold=<N>

Configure the number of transitions between survivor spaces before an object is moved to OldGen.

Because IG largely consumes YoungGen space, we can determine that anything that eventually would live in OldGen space could be moved there early to free up Eden space and reduce objects transitioning between survivor spaces. We could therefore set -MaxTenuringThreshold to a low value, possibly as low as 1 to accomplish this.

GSA: Good, this is exactly the kind of description that is useful to our users: it explains why this is worth considering this option

WM: Thanks

(Will remove Tuesday 30/6/2020 if no further comment)

-XX:MetaspaceSize=<size>G

-XX:MaxMetaSpaceSize=<size>G

Configure initial and maximum Metaspace size (from java 8). IG 

GSA: Unsure if we should keep this one in the doc, for sure not in the first positions, it's relatively less important than young/old gen settings

WM: Probably not vital but it is included in other guides and I think it's important to note we only need a smallish Metaspace. I've moved it to last position, as I want to describe it as II've provided a recommended default

(Will remove Tuesday 30/6/2020 if no further comment)

Garbage collection (GC)

Selecting the right garbage collector and tuning collection can reduce expensive "stop the world" pauses in collection. As IG is largely a consumer of YoungGen memory, there is a lot of scope for tuning to avoid expensive major collections (OldGen space consumption).

As mentioned, it is generally advisable to select from available, stable garbage collectors for the given JVM version according to your performance targets. Each garbage collector has its own goals and algorithms supporting that goal. For example, The Parallel GC aims to increase throughput whereas GCG1 aims to reduce latency. It is therefore advisable to test and compare.

GSA: Do not talk about CMS at all: we need Java 11 anyway, so this is not an option

WM: Ok, removed. I had included it as a transition point for users moving from java 8, to give a clear picture that CMS is now deprecated.

(Will remove Tuesday 30/6/2020 if no further comment)

Parallel GC

  • Default Hotspot collector in java 8 - in resource-rich environment (multiprocessor, memory availability).
  • Multiple threads for managing heap-space speeds up collection process.
  • Aims to maximise throughput.
  • Requires more full-GCs ("stop-the-world"), freezing application threads while in progress.

The following Parallel GC options are worth considering:


GSA: If we don't provide added values, I would not bother adding these things in our doc, a pointer to the official doc page would be enough (and easier to maintain)

Added value like: why this is interesting for IG, or return of experience like we observed a noticeable impact when ...

WM: When you say added value though, the below is taken from looking into multiple GC tests and guides, and is intended only as a guide for IG to consolidate info (without having done exhaustive testing). I think it's therefore still very useful. 

(Will remove Tuesday 30/6/2020 if no further comment)

OptionDescription
-XX:+UseParallelGCUse the Parallel garbage collector.
-XX:MaxGCPauseMillis=<duration in milliseconds>Supports configuration of the target max time to pause in GC. This is purely a goal and not guaranteed. It does, however, allow some configuration between throughput (longer pauses) and latency (shorter pauses). Test values between 500ms - 2000ms.
-XX:GCPauseTimeInterval=<duration in milliseconds>Supports configuration of the ideal max time between pauses in GC. This is purely a goal and not guaranteed. It does, however, allow some configuration between throughput (longer pauses) and latency (shorter pauses). Test values between 500ms - 2000ms.
-XX:GCTimeRatio=<percent value>Supports configuration of the optimal ratio between time in GC and application time. This ratio is 1% by default and should not be configured to be greater than 5%.
-XX:ParallelGCThreads=<size> Number of threads to use in parallel operations

-XX:YoungGenerationSizeIncrement 

-XX:TenuredGenerationSizeIncrement

-XX:AdaptiveSizeDecrementScaleFactor

Adaptive sizing of each generation can be controlled using parameters using these parameters. The default increment is 20%. The -XX:AdaptiveSizeDecrementScaleFactor is the percentage to decrease on decrement, as a factor of the increment size. Default is 5%.

The following is an example set of JVM options using the Parallel GC (GC logging omitted):

JVM options with Parallel GC
-XX:InitialHeapSize=5g -XX:MaxHeapSize=5g \
-XX:NewSize=2G -XX:MaxNewSize=4G \
-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M \
-XX:MaxTenuringThreshold=1 \
-XX:+UseStringDeduplication \
-XX:+UseParallelGC \
-XX:MaxGCPauseMillis=500

Garbage-First GC (G1) 

GSA: I've never seen G1 been called G1GC, usually it's just G1

WM: In all the docs I've read, I've seen it called G1, G1 GC and G1GC. Oracle seem to use G1 GC - Happy to revert though.

(Will remove Tuesday 30/6/2020 if no further comment)

  • Available since java 7u4 and the default HotSpot collector since java 9 (in resource-rich environments).
  • A "Mostly Concurrent Collector", meaning a parallel, concurrent, and incrementally compacting low-pause collector.
  • Concurrent collector, which conducts expensive operations concurrently with the application threads. 
  • Designed for multiprocessor environments with large available memory with the intent of good overall performance without the need to specify additional options.
  • Partitions heap into equal sized regions, each with a contiguous range of virtual memory.
  • Minimises collection pauses in multiprocessor, memory-rich environments - reduces GC latency.
  • Uses an internal adaptive optimization algorithm to manage available heap-space, meaning it's adaptive to fast-memory growth/ spikes in load but also scales efficiently with lower load. With G1GC, this overrides -Xms  increments.
  • Recommended to use G1 GC with heap size set to ensure optimal region sizing. See testing here

The following G1 options are worth considering:

OptionDescription
-XX:+UseG1GCUse the G1 garbage collector.
-XX:MaxGCPauseMillisSupports configuration of the target max time to pause in GC. This is purely a goal and not guaranteed. It does, however, allow some configuration between throughput (longer pauses) and latency (shorter pauses). Test values between 500ms - 2000ms.
-XX:GCPauseTimeIntervalSupports configuration of the ideal max time between pauses in GC. This is purely a goal and not guaranteed. It does, however, allow some configuration between throughput (longer pauses) and latency (shorter pauses). Test values between 500ms - 2000ms.
-XX:GCTimeRatioSupports configuration of the optimal ratio between time in GC and application time. This ratio is 1% by default and should not be configured to be greater than 5%.
-XX:ParallelGCThreads=<size> Number of threads to use in parallel operations - notably "stop-the-world" activities. It is recommended to set this to the number of logical cores, if this value is less than 8. Otherwise, generally, set it to 5/8 of the number of cores.
-XX:ConcGCThreads=<size> Number of threads to use in concurrent operations - notably marking, which may reduce pauses. It is recommended  to be 1/4 of the -XX:ParallelGCThreads value.

-XX:G1NewSizePercent=<%>

-XX:G1MaxNewSizePercent=<%>

Supports managing the YoungGen space allocation as a percentage of the overall heap size. Ordinarily, this is best left unset to be managed by the G1 adaptive optimisation algorithm, but could be used as a hint, given our understanding of IG's YoungGen usage.
-XX:G1HeapRegionSize Not recommended as it's an ergonomic setting based on heap size. It can be used, however, to manage the heap region size - to fine-tune how objects are allocated - which may be beneficial if large resources are being processed.

The following is an example set of JVM options using the G1GC (GC logging omitted):

Useful G1GC configuration options
-XX:InitialHeapSize=5g -XX:MaxHeapSize=5g \
-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M \
-XX:MaxTenuringThreshold=1 \
-XX:+UseStringDeduplication \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=500\

References

  1. KB FAQ: IG Performance and Tuning
  2. KB BestPractice: Best practice for JVM Tuning (java 7)
  3. KB HowTo: How do I collect JVM data for troubleshooting IG/OpenIG (All versions)?
  4. KB HowTo: How do I enable Garbage Collector (GC) Logging for IG/OpenIG (All versions)?
  5. DZone: Choosing the Right GC
  6. Oracle Garbage Collection Tuning Guide
  7. Oracle G1GC Tuning Guide
  8. JVM Tuning with G1GC by @marknienaber on medium.com (our very own Mark Nienaber (S))
  9. Improving G1 Out-of-the-box Performance by Stefan Joansson
  10. High Performance at Low Cost – Choose the Best JVM and the Best Garbage Collector for your Needs by Jonatan Kazmierczak
  11. A Step-by-step Guide to Java Garbage Collection Tuning by Rafal Kuc
  12. Reduce Long GC Pauses by gceasy.io

  • No labels