G1GC is mainly designed for one thing, keeping your application responsive by:

trying to avoid that garbage collection of the "old gen" (the tenured objects that the application has hold on to for some time, like from a user session, cache, or some kind of memory leak) must be done in a single classic FullGC where your application is frozen while the entire heap has to be cleaned (which depending on the number of objects may take a long time, like several seconds. Read all about it here, one quote from it:

The goal is to reclaim as much heap space as possible (starting with those regions that contain the most reclaimable space) while attempting to not exceed the pause time goal

The 40% you set for the: InitiatingHeapOccupancyPercent relate to the (entire) heap occupancy and denote when to start a concurrent GC cycle (this should be visible in the logs, if not see: this related question ). GCs that trigger a concurrent GC cycle based on the occupancy of the entire heap and not just one of the generations (so not just Old Gen), including G1, use this option. A value of 0 denotes 'do constant GC cycles'. The default value is 45. (Adapted from: Oracle® Communications WebRTC Session Controller System Administrator's Guide )

So it is possible that:

  1. The GC cycle is initiated at 40% heap occupancy but before it is finished you reach a much higher level (like 90%), which may be entirely fine as long as your application is working
  2. You have some kind of memory leak (but that is hard to tell from the graph without knowing the application and how long it is running or see how it plays out after a longer time)
  3. There may be some other problems but it is impossible to tell without having the garbage collection logs to analyse, but you may want to refer to: Monica Beckwith's article on G1GC e.g. the part on Evacuation Failure

If you really want your application to use less memory (maybe at the price of some loss in performance/throughput) you could lower the MaxHeapSize (but you should use either one of: MaxRAMFraction or MaxHeapSize (XmX), not both).

Or depending on your application and performance requirements consider going for an entirely different JVM/Garbage Collector like:

  • IBM/Eclipse OpenJ9 (see: https://developer.ibm.com/articles/garbage-collection-tradeoffs-and-tuning-with-openj9/ which is touted as having a very low memory overhead)
  • or any other GC mentioned in this research on Java memory elasticity discussing Shenandoah, ZGC, C4 and many others
Answer from JohannesB on Stack Overflow
Top answer
1 of 1
4

G1GC is mainly designed for one thing, keeping your application responsive by:

trying to avoid that garbage collection of the "old gen" (the tenured objects that the application has hold on to for some time, like from a user session, cache, or some kind of memory leak) must be done in a single classic FullGC where your application is frozen while the entire heap has to be cleaned (which depending on the number of objects may take a long time, like several seconds. Read all about it here, one quote from it:

The goal is to reclaim as much heap space as possible (starting with those regions that contain the most reclaimable space) while attempting to not exceed the pause time goal

The 40% you set for the: InitiatingHeapOccupancyPercent relate to the (entire) heap occupancy and denote when to start a concurrent GC cycle (this should be visible in the logs, if not see: this related question ). GCs that trigger a concurrent GC cycle based on the occupancy of the entire heap and not just one of the generations (so not just Old Gen), including G1, use this option. A value of 0 denotes 'do constant GC cycles'. The default value is 45. (Adapted from: Oracle® Communications WebRTC Session Controller System Administrator's Guide )

So it is possible that:

  1. The GC cycle is initiated at 40% heap occupancy but before it is finished you reach a much higher level (like 90%), which may be entirely fine as long as your application is working
  2. You have some kind of memory leak (but that is hard to tell from the graph without knowing the application and how long it is running or see how it plays out after a longer time)
  3. There may be some other problems but it is impossible to tell without having the garbage collection logs to analyse, but you may want to refer to: Monica Beckwith's article on G1GC e.g. the part on Evacuation Failure

If you really want your application to use less memory (maybe at the price of some loss in performance/throughput) you could lower the MaxHeapSize (but you should use either one of: MaxRAMFraction or MaxHeapSize (XmX), not both).

Or depending on your application and performance requirements consider going for an entirely different JVM/Garbage Collector like:

  • IBM/Eclipse OpenJ9 (see: https://developer.ibm.com/articles/garbage-collection-tradeoffs-and-tuning-with-openj9/ which is touted as having a very low memory overhead)
  • or any other GC mentioned in this research on Java memory elasticity discussing Shenandoah, ZGC, C4 and many others
Discussions

InitiatingHeapOccupancyPercent tuning parameter value modification ( 75 to 30 )from 7.0.1 version to 7.8.0 in G1GC for elasticsearch
"InitiatingHeapOccupancyPercent" parameter is set to 75 for elasticsearch 7.0.1, which is now updated to 30. Please state the reason why was it changed and what effect did it have. 7.0.1 version's jvm.options snippet: ## G1GC Configuration # NOTE: G1GC is only supported on JDK version 10 or later. More on discuss.elastic.co
🌐 discuss.elastic.co
0
0
August 20, 2020
java - Why doesn't G1 start a marking cycle when the InitiatingHeapOccupancyPercent is achieved? - Stack Overflow
According to the documentation, XX:InitiatingHeapOccupancyPercent Sets the Java heap occupancy threshold that triggers a marking cycle. The default occupancy is 45 percent of the entire Java h... More on stackoverflow.com
🌐 stackoverflow.com
Weird behavior with G1GC after upgrading to Java 11
If you are using Correto, there used to be a bug with its g1gc implementation, which caused a similar issue on my end, not sure if it was fixed, in our case we migrated to shenandoah, which behaved better More on reddit.com
🌐 r/java
11
26
June 26, 2023
Java Options for SMP
Major problems: Quoting from Bukkit admin : -Xnoclassgc - this flag should not be used with CraftBukkit as we make EXTENSIVE use of reflection and could lead to a large memory leak as a result of all the dynamic classes not being garbage collected when they need to be, since you are telling it not to… You are running a snapshot server, but keep in mind that there's no reason to disable class garbage collection in the first place, and you may run into issues later on. Performance cost is negligible. - -XX:ConcGCThreads=4 specifies the number of threads for a concurrent collector, which has nothing to do with the G1 collector. Your day and night anecdote is an obvious placebo, because that flag doesn't do anything when used with a non-CMS collector. In addition, you shouldn't be specifying the number of threads your GC runs on anyways. -XX:InitiatingHeapOccupancyPercent=0 "When it works continuously, it may take some performance away from the game, but it allows the garbage collector to keep up, which I think is much more important." If you want something that works continuously, use the incremental collector. It's pretty bad in terms of throughput, and is not recommended on anything but extremely low end systems. -server forces the HotSpot collector for 32 bit older Java versions, and does nothing whatsoever on 64-bit Java: http://stackoverflow.com/questions/198577/real-differences-between-java-server-and-java-client -XX:+DisableExplicitGC This probably has no effect unless you run with the server GUI. Wut. OP is really feeling the placebo effect. With no heap profiling reports and anecdotal "evidence" for options that do absolutely nothing, as well as the fact that garbage collection will definitely not be your bottleneck in most cases. If you're running a snapshot server, you probably don't even have that many players anyways, and the default collector will be good enough. If you claim that you've tested all the collectors, I'd like to see some numbers, as CMS appears to be the standard for low-latency medium-throughput applications. More on reddit.com
🌐 r/admincraft
18
0
July 28, 2014
🌐
Oracle
docs.oracle.com › cd › E40972_01 › doc.70 › e40973 › cnf_jvmgc.htm
Tuning JVM Garbage Collection for Production Deployments
-XX:InitiatingHeapOccupancyPercent: Percentage of the (entire) heap occupancy to start a concurrent GC cycle. GCs that trigger a concurrent GC cycle based on the occupancy of the entire heap and not just one of the generations, including G1, use this option.
🌐
GC easy
blog.gceasy.io › home › simple & effective java g1 gc tuning tips
Simple & effective Java G1 GC tuning tips - GC easy - Universal Java GC Log Analyser
March 30, 2026 - Start the marking cycle earlier by reducing the ‘-XX:InitiatingHeapOccupancyPercent’. The default value is 45. Reducing the value will start the marking cycle earlier.
🌐
Oracle
docs.oracle.com › en › java › javase › 21 › gctuning › garbage-first-g1-garbage-collector1.html
HotSpot Virtual Machine Garbage Collection Tuning Guide
October 20, 2025 - If this feature is active, then the option -XX:InitiatingHeapOccupancyPercent determines the initial value as a percentage of the size of the current old generation as long as there aren't enough observations to make a good prediction of the Initiating Heap Occupancy threshold.
🌐
Super User
superuser.com › questions › 1497068 › how-does-ihop-calculated-in-g1-gc-for-starting-concurrent-marking-cycle
java - How does IHOP calculated in G1 GC for starting concurrent marking cycle? - Super User
October 29, 2019 - -XX:InitiatingHeapOccupancyPercent=percent Sets the percentage of the heap occupancy (0 to 100) at which to start a concurrent GC cycle.
🌐
Krzysztofslusarski
krzysztofslusarski.github.io › 2021 › 08 › 16 › monday-mixed.html
[Java][JVM Logs][GC Logs][G1GC] Monday with JVM logs - efficiency of the old generation cleanup | JVM/Java profiling and tuning
August 16, 2021 - If this feature is active, then the option -XX:InitiatingHeapOccupancyPercent determines the initial value as a percentage of the size of the current old generation as long as there aren’t enough observations to make a good prediction of the Initiating Heap Occupancy threshold.
Find elsewhere
🌐
Elastic
discuss.elastic.co › elastic stack › elasticsearch
InitiatingHeapOccupancyPercent tuning parameter value modification ( 75 to 30 )from 7.0.1 version to 7.8.0 in G1GC for elasticsearch - Elasticsearch - Discuss the Elastic Stack
August 20, 2020 - "InitiatingHeapOccupancyPercent" parameter is set to 75 for elasticsearch 7.0.1, which is now updated to 30. Please state the reason why was it changed and what effect did it have. 7.0.1 version's jvm.options snippet: ## G1GC Configuration # NOTE: G1GC is only supported on JDK version 10 or later.
🌐
ycrash Answers
answers.ycrash.io › question › how-can-i-adjust-jvm-parameters-to-improve-performance
How can I adjust jvm parameters to improve performance? - yCrash Answers
November 17, 2023 - On the other hand, if the marking cycle is starting early and not reclaiming, increase the -XX:InitiatingHeapOccupancyPercent threshold above the default value. 4. You can also increase the value of the '-XX:ConcGCThreads' argument to increase the number of parallel marking threads.
Top answer
1 of 1
16

JDK-6976060 suggests that the need for a marking cycle is calculated at the end of a young GC. Depending on whether it uses the occupancy stats before or after the young GC this may or may not mean that eden space is always considered as 0% occupied for the purpose of IHOP calculation. With a 45% eden size that would mean 70% occupancy could never be reached, the maximum possible occupancy would be 55% and at that point the heap would be completely full and it would be too late for a mixed collection.

But I am doubtful whether this is truly the case because in the face of dynamic young generation sizing this would make the documentation misleading and IHOP tuning far more difficult. It should be fairly easy to verify this with an artificial test-case and manually sized generations.

If that's not the issue then GC pause (GCLocker Initiated GC) (young) might point to bug 8140597, which is fixed in jdk9b94.


Update: The description in Bug 8151176 indeed suggests that for the purpose of the IHO-percentage calculation it calculates oldgen occupancy/overall heap size. Which means young generation occupancy is completely ignored, which in turn means if young gen fraction > IHOP then it can never initiate a concurrent cycle.

The reason is that static IHOP starts if old gen occupancy exceeds a fixed percentage of the current heap capacity. If either the user or ergonomics decide that the old gen can not be larger than that fraction of the heap capacity that triggers concurrent mark, marking will never start.

So currently available solutions are

  • constrain the young gen fraction < IHOP
  • decrease IHOP to take the minimum possible old gen fraction into account
  • let the JVM adjust the IHOP dynamically

Update2: The latest comment on that bug indicates that this has been fixed for some time, so this answer should be considered as historic.

🌐
Medium
fnote.medium.com › g1gc-tuning-ec78d40861d
G1GC tuning. What is G1GC ? | by F Notes | Medium
December 26, 2019 - -XX:+UseG1GC disabled enableduse ... versus at incrementally at runtime -XX:InitiatingHeapOccupancyPercent45%%start marking when heap is...
🌐
Oracle
docs.oracle.com › javase › 8 › docs › technotes › guides › vm › gctuning › g1_gc.html
9 Garbage-First Garbage Collector
April 21, 2026 - Set the value of this parameter with the command-line option -XX:InitiatingHeapOccupancyPercent=<NN>. The default value of InitiatingHeapOccupancyPercent is 45.
🌐
OpenJDK
bugs.openjdk.org › browse › JDK-8227106
InitiatingHeapOccupancyPercent is G1-specific but defined in ...
July 2, 2019 - The command line option InitiatingHeapOccupancyPercent is G1-specific, both in usage and noted as such in the describing string. But it is defined in shard/gc_globals.hpp rather than g1/g1_globals.hpp.
🌐
Sematext
sematext.com › home › blog › a step-by-step guide to java garbage collection tuning
A Step-by-Step Guide to Java Garbage Collection Tuning
January 14, 2020 - Once that threshold is hit, G1 ... -XX:InitiatingHeapOccupancyPercent flag which controls the Initial Mark collection is the initial value that is further adjusted by the garbage collector....
🌐
Cloudera Community
community.cloudera.com › t5 › Support-Questions › How-should-I-set-InitiatingHeapOccupancyPercent-of-G1GC-for › td-p › 180782
How should I set InitiatingHeapOccupancyPercent of G1GC for NameNode with high usage of jvm heap
September 8, 2017 - Now I are trying to change GC from CMS to G1GC. And let's say, current situation of NameNode with CMS are Physical memory size : 140 GB -Xmx100G -Xms100G current actual heap usage : 70 - 80 GB (So, usage is around 80%.) -XX:InitiatingHeapOccupancyPercent : 90 The default value of "-XX:InitiatingHeap...
🌐
Medium
medium.com › @kaustubh.saha › g1-gc-8703990c2691
G1 GC. Garbage Collection (GC) is one of the… | by Kaustubh Saha | Medium
October 5, 2025 - -XX:initiatingHeapOccupancyPercent=45 ## default value - This means that by default, the G1 collector will attempt to start a concurrent marking cycle when the overall Java heap is 45% full.