Memory Managment: Young Gen Clarification - java

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.

Related

JVM -Xmn memory

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.

Survival full, does Tenured generation GC run?

I am trying to understand how Java GC works. Let assume that due to an allocation request, the Eden space is full. Minor GC happens, collecting all Eden and Survival1 objects into Survival2. But there are more objects than space in Survival2. As far as I understand, when this happens, the spillover is moved to the Tenured space (prematurly?—as in, before the predefined number of GC iterations that an object is supposed to stay in the Young space). Does such an event also trigger a GC for the Tenured space if the Tenured space has enough space for the spillover?
I'm not considering the G1 garbage collection here.
Your assumption about how the survivor spaces work is correct. If the 'to' survivor space does not have enough space for objects being copied from the 'from' space plus those that have been collected from Eden, objects will be prematurely promoted (before the tenuring threshold has been reached) to the old generation.
The old gen. is separate so a GC will only be triggered if the objects being promoted from the Young gen. cause it. With algorithms like CMS and G1, they use values like the occupancy fraction to decide when to initiate GC. GC of the old gen. may be triggered if there is still enough space for the promotion but it's not a certainty.

What cause Objects to move from Young Generation to Old Generation

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.

JVM YoungGen 0%, Perm Gen 99%, OldGen Full

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

MaxTenuringThreshold - how exactly it works?

We know that there's few main memory domains: Young, Tenured (Old gen) and PermGen.
Young domain is divided into Eden and Survivor (with two).
OldGen is for surviving objects.
MaxTenuringThreshold keeps objects from being finally copied to the OldGen space too early. It's pretty clear and understandable.
But how does it work? How is the garbage collector dealing with these objects which are still surviving till MaxTenuringThreshold and in what way? Where are they located?
Objects are being copied back to Survivor spaces for garbage collection.. or does it happen somehow else?
Each object in Java heap has a header which is used by Garbage Collection (GC) algorithm. The young space collector (which is responsible for object promotion) uses a few bit(s) from this header to track the number of collections object that have survived (32-bit JVM use 4 bits for this, 64-bit probably some more).
During young space collection, every single object is copied. The Object may be copied to one of survival spaces (one which is empty before young GC) or to the old space. For each object being copied, GC algorithm increases it's age (number of collection survived) and if the age is above the current tenuring threshold it would be copied (promoted) to old space. The Object could also be copied to the old space directly if the survival space gets full (overflow).
The journey of Object has the following pattern:
allocated in eden
copied from eden to survival space due to young GC
copied from survival to (other) survival space due to young GC (this could happen few times)
promoted from survival (or possible eden) to old space due to young GC (or full GC)
the actual tenuring threshold is dynamically adjusted by JVM, but MaxTenuringThreshold sets an upper limit on it.
If you set MaxTenuringThreshold=0, all objects will be promoted immediately.
I have few articles about java garbage collection, there you can find more details.
(Disclaimer: This covers HotSpot VM only)
As Alexey states, the actually used tenuring threshold is determined by the JVM dynamically. There is very little value in setting it. For most applications the default value of 15 will be high enough, as usually way more object survive the collection.
When many objects survive the collection, the survivor spaces overflow directly to old. This is called premature promotion and an indicator of a problem. However it seldom can be solved by tuning MaxTenuringThreshold.
In those cases sometimes SurvivorRatio might be used to increase the space in the survivor spaces, allowing the tenuring to actually work.
However, most often enlarging the young generation is the only good choice (from configuration perspective).
If you are looking from coding perspective, you should avoid excess object allocation to let tenuring work as designed.
To answer exactly what you asked:
When an object reaches its JVM determinded tenuring threshold, it is copied to old. Before that, it will be copied to the empty survivor space. Objects that have been surviving a while but are de-referenced before reaching the threshold are cleaned from survivor very efficiently.

Categories

Resources