What happens when Java’s survivor space is full but the Eden’s space has free memory? Does the survivor space uses the Eden’s space?
What happens when Java’s Survivor space is full but the Eden’s space has free memory?
It will depend on the GC. And it also, on whether the Survivor space is at the max (as distinct from just being full). But shrinking Eden space to allow the Survivor space to grow is one possible strategy.
Note: shrinking Eden space won't be good for performance. It is liable to increase the rate of minor GCs, and ultimately major GCs.
I took a brief look at the source code for the G1 collector in JDK 17. It appears1 that G1GC has no provision for shrinking Eden space. (Look at the file "/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp")
1 - Caveat: the context of the code I looked at is complicated, and I could easily have misunderstood it. YMMV.
Related
My jvm memory allocation scheme.
-Xms2048m -Xmx2048m -Xmn1536m
The official recommendation is that the young generation is 3/8 of the heap memory.
if the memory allocated by my -Xmn is small or large. What effect will it have?
The size of the young generation will determine the time between minor GCs. Objects are allocated in the Eden space using a simple pointer bumping approach, which is very fast (for multiple threads it is a bit more complicated by having thread local allocation blocks to eliminate the issue of contention). The bigger your Eden space, the longer your application can create objects before the allocation pointer(s) reach the end of the address space.
When no more objects can be allocated in Eden space, a minor GC is performed that copies live objects from Eden to a survivor space and promotes objects that have reached the tenuring threshold to the old generation. Most objects are very short-lived (the weak generational hypothesis) so, typically, only a small number of objects need to be copied. Making your Eden space larger will also mean more objects have a chance to be dereferenced and you will end up placing a lower load on the old generation.
The 3/8 advice is good for a wide range of applications. Obviously, for different applications, you may tune this up or down to fit the memory usage profile. One important rule to follow though is to keep the young generation less than 50% of the heap space (i.e. the young generation should always be smaller than the old generation). The reason for this is that, if not, the collector will run a major GC every time a minor GC is run. This is because the collector needs to ensure there is enough space in the old gen to promote objects from the young gen.
After many cycles of GC, Objects that are survived in young generation are moved to the Old generation memory space.
Please clarify, Minor GC is responsible for this ? or Major GC?
Please clarify, Minor GC is responsible for this ? or Major GC?
Either of them is responsible for object to move from young gen to old gen.
Have a look at "General Garbage Collection Process" section # oracle garbage collection tutorial
Summary:
First, any new objects are allocated to the eden space. Both survivor spaces start out empty.
When the eden space fills up, a minor garbage collection is triggered
Referenced objects are moved to the first survivor space. Unreferenced objects are deleted when the eden space is cleared.
At the next minor GC, the same thing happens for the eden space. Unreferenced objects are deleted and referenced objects are moved to a survivor space. However, in this case, they are moved to the second survivor space (S1)
At the next minor GC, the same process repeats. However this time the survivor spaces switch. Referenced objects are moved to S0. Surviving objects are aged. Eden and S1 are cleared.
After a minor GC, when aged objects reach a certain age threshold (8 in this example) they are promoted from young generation to old generation.
As minor GCs continue to occur, objects will continue to be promoted to the old generation space.
Eventually, a major GC will be performed on the old generation which cleans up and compacts that space.
Objects can be moved from young to tenured space in either a Minor GC (young space) or Full GC (everything). A Major GC collection only collects in the tenured space.
Smaller objects are created in the Eden space, Large obejcts e.g. arrays in the tenured space.
When the Eden space is cleared out, surviving objects are copied to the survivors spaces. They are copied back and forth between the two survivors spaces until their age (number of times copied) reaches the tenuring threshold and in which case it is copied to the tenured space.
If there is too many objects in the Eden space to be copied to the survivor spaces, a full GC is triggered and all live object go straight to the tenured space.
Considering the size (survivorRatio) survivor size will always be greater than eden
The survivor ratio is how much smaller the survivor space is than the Eden space. e.g. -XX:SurvivorRatio=8 means the survivors space is 1/10th of young generation. There is two survivors spaces (1/10th each) and the Eden space is 8 times larger (8/10ths)
Even if the survivors space was larger than the Eden, it's the amount of free space in the survivor which matters. You could have a survivor space which is 90% full for example (as it still has objects from the last N collections)
So will there be ever a scenario to have that objects directly gets copied from eden to Old if objects are smaller in size (not humongous) ?
If you make the survivor spaces small enough to trigger a full collection each time, the objects will go from Eden to Tenured. I don't recommend going this.
Heap memory is divided into Young Gen, Old Gen and PermGem.
In young gen, one eden space and two survivor spaces are allocated. According to GC in our machines, one survivor space should always be available so that the next live nodes references can be stored there when GC marks the already present references (scans) in the young gen (eden space + 1 survivor space) and upgrade them to old gen.
First question is, is this understanding correct?
If yes, at all the times some portion of Young Gen will be vacant/available in the form of 1 survivor space. So how to see in GC Logs that the young gen is full (i.e. GC is triggered) or that is misleading? which means only usable young gen memory is shown to us in GC logs.
How to analyse the Heap memory is full i.e. OutOfMemory when some portion of Young Gen will always be having some vacant space, hence the all around heap memory.
Thanks in advance.
There are 2 kinds of GC collections
Minor GC - this occurs when the young generation fills up
Full GC - this occurs when the tenured or the old generation fills up.
An OutOfMemory occurs when there is no space left on the heap to move objects into the old generation.
You should read up more on Java GC process. You can start with - http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
To read and analyze the GC logs you can refer to How to read a verbose:GC output?
Assuming you're using hotspot then logging with -XX:+PrintGCDetails -XX:+PrintHeapAtGC should be verbose enough to cover all the things you're interested on.
I have a JEE application that has recently started to see spikes in CPU usage (e.g. 100% of 27 cores on a 40 core server) and increasingly longer periods of time where the application is unavailable. It's very similar behavior to the issue described in the following post, to include the fact that bouncing the application server makes the issue go away until it appears again after a few hours:
Old Gen heap is full and the Eden and Survivor are low and almost empty
I've taken some core dump outputs while the application is experiencing these "freezes" and I am seeing the following JVM GC output:
PSYoungGen total 11221504K, used 2435K
eden space 9238528K, 0% used
from space 19829796K, 0% used
to space 1970176K, 0% used
ParOldGen total 39613440K, used 39276477K
object space 39613440K, 99% used
PSPermGen total 254976K, used 115497K
object space 254976K, 45% used
Based on the referenced post and the above output, I think I understand that the "freezes" are being driven by the garbage collector running (in vain?) on the ParOldGen space. The parts I am missing:
Why the PermGen space remains at 45% used. That is, will the ~39GB of stuff in ParOldGen ultimately transition into PSPermGen?
What is the significance of the nearly empty PSYoungGen space? Does this mean that the application isn't creating any/many new object instances at steady state?
The post above also describes the option of "giving more headroom" to ParOldGen, but I'm not clear if that means increasing the total heap size via -Xmx or if there's an explicit JVM GC parameter. I see the NewRatio argument controls the size of the young generation relative to the old generation. Would the fact that the PSYoungGen is essentially empty mean that it's too large, and that I should use a smaller NewRatio value?
Thanks in advance for any assistance.
will the ~39GB of stuff in ParOldGen ultimately transition into PSPermGen?
The PermGen in Java 7 (replaced with metaspace in Java 8) is for holding code. The only things which pass from the heap to PermGen is byte code, so unless you are generating or loading classes, nothing passes from one to the other. They are different spaces.
What is the significance of the nearly empty PSYoungGen space?
The young gen is empty after a full GC. Full GCs are common once your old gen starts to fill up.
Does this mean that the application isn't creating any/many new object instances at steady state?
It is more likely to mean it has recently Full GC-ed.
describes the option of "giving more headroom" to ParOldGen, but I'm not clear if that means increasing the total heap size via -Xmx or if there's an explicit JVM GC parameter.
Increasing the maximum heap could give you more head room, but I would first check
you don't have a memory leak.
you can't move the bulk of your data off heap e.g. a database or native memory.
Would the fact that the PSYoungGen is essentially empty mean that it's too large, and that I should use a smaller NewRatio value?
That could help give you more space for the old gen, but it might just give you a bit more time before it runs out of memory.
Why the PermGen space remains at 45% used. That is, will the ~39GB of stuff in ParOldGen ultimately transition into PSPermGen?
No. OldGen & PermGen spaces can't be shared. PSPermGen mostly contains classes loaded by class loader in PermGen space. ParOldGen contains heap memory for long lived objects.
In JDK 1.8, PermGen has replaced by Metaspace. Refer to this article for more details.
Refer to below SE questions for more details:
Java heap terminology: young, old and permanent generations?
What is the significance of the nearly empty PSYoungGen space? Does this mean that the application isn't creating any/many new object instances at steady state?
#Peter Lawrey has correctly answered it. After Full GC, YoungGen is nearly empty => you did not accumulate garbage from short lived objects in your application
The post above also describes the option of "giving more headroom" to ParOldGen, but I'm not clear if that means increasing the total heap size via -Xmx or if there's an explicit JVM GC parameter.
Your old gen is full implies that your application is retaining heap from long lived objects.
Now you have to check possible memory leaks (if any) in your application using profiling tools like visualvm or MAT
If you don't have memory leaks, you can increase your heap size with -Xmx.
Would the fact that the PSYoungGen is essentially empty mean that it's too large, and that I should use a smaller NewRatio value?
Since you are using larger heaps, I recommend you to use G1GC algorithm. If you use G1GC algorithm, don't customize default values since G1GC algorithm takes care of better heap management.
Have a look at oracle article on G1GC switches (Complete List of G1 GC Switches section), Use Cases article and related SE question:
Java 7 (JDK 7) garbage collection and documentation on G1
What is the criteria to put a young object in an old region making it an old object or keep it in survivor regions?
The point 4 of Young GC of the official tutorial state:
"Live objects are evacuated (i.e., copied or moved) to one or more
survivor regions. If the aging threshold is met, some of the objects
are promoted to old generation regions."
But I can't find what that criteria is.
EDIT:
Amit Bhati pointed me to the MaxTenuringThreshold parameter. I don't understand much from the official doc about it but I think I started to understand how it works.
With your help I think I found the answer here:
-XX:InitialTenuringThreshold=7 Sets the initial tenuring threshold for use in adaptive GC sizing in the parallel young collector. The
tenuring threshold is the number of times an object survives a young
collection before being promoted to the old, or tenured, generation.
-XX:MaxTenuringThreshold=n Sets the maximum tenuring threshold for use in adaptive GC sizing. The current largest value is 15. The default
value is 15 for the parallel collector and is 4 for CMS.
It is under the Debugging Options title :)
Under Garbage First (G1) Garbage Collection Options you can find this:
-XX:MaxTenuringThreshold=n Maximum value for tenuring threshold. The default value is 15.
It is not very descriptive if you have not read InitialTenuringThreshold description on the other section. It seems InitialTenuringThreshold is not a valid G1 option but I think the algorithm is the described there.
The following doc is good at explaining how to alter (reduce) the rate at which items are promoted from the survivor spaces to the Old Gen in the G1 collector.
http://java-is-the-new-c.blogspot.co.uk/2013/07/tuning-and-benchmarking-java-7s-garbage.html (the section entitled Tuning The Young Generation)
As the above answers say, the MaxTenuringThreshold is the key setting, but this is only an upper limit, and would be ignored if your YoungGen wasn't big enough to allow this to be honoured. In which case you'd need to increase either the overall YoungGen via NewRatio or just the SurvivorSpace via SurvivorRatio
From the Javadocs:
The heap space is divided into the old and the new generation. The new
generation includes the new object space (eden), and two survivor
spaces. The JVM allocates new objects in the eden space, and moves
longer lived objects from the new generation to the old generation.
The young generation uses a fast copying garbage collector which
employs two semi-spaces (survivor spaces) in the eden, copying
surviving objects from one survivor space to the second. Objects that
survive multiple young space collections are tenured, meaning they are
copied to the tenured generation. The tenured generation is larger and
fills up less quickly. So, it is garbage collected less frequently;
and each collection takes longer than a young space only collection.
Collecting the tenured space is also referred to as doing a full
generation collection.
The frequent young space collections are quick (a few milliseconds),
while the full generation collection takes a longer (tens of
milliseconds to a few seconds, depending upon the heap size).
Other GC algorithms, such as the Concurrent Mark Sweep (CMS)
algorithm, are incremental. They divide the full GC into several
incremental pieces. This provides a high probability of small pauses.
This process comes with an overhead and is not required for enterprise
web applications.
Also check this article: Java Garbage Collectors – Moving to Java7 Garbage-First (G1) Collector
The young generation comprises of one Eden and two Survivor spaces.
The live objects in Eden are copied to the initially empty survivor
space, labeled S1 in the figure, except for ones that are too large to
fit comfortably in the S1 space. Such objects are directly copied to
the old generation. The live objects in the occupied survivor space
(labeled S0) that are still relatively young are also copied to the
other survivor space, while objects that are relatively old are copied
to the old generation. If the S1 space becomes full, the live objects
from Eden or S0 that have not been copied to it are tenured,
regardless of their age. Any objects remaining in Eden or the S0 space
after live objects have been copied are not live and need not be
examined. Figure below illustrates the heap after young generation
collection:
The young generation collection leads to stop the world pause. After
collection, eden and one survivor space are empty. Now let’s see how
CMS handles old generation collection. It essentially consists of two
major steps – marking all live objects and sweeping them.