To understand how Java applications run, and how they differ from other types of applications, it is first important to understand the nature of the Java Virtual Machine and the Java memory management allocation processes. Therefore, before proceeding with this knowledge base article we strongly recommend that you first review our knowledge base article on Java Memory Management: https://www.fredhopper.com/learningcenter/x/vyJwAQ
Generational Collections
The Java Virtual Machine manages memory in a "generational" manner, so objects are created in the Eden Generation, and then depending on whether they remain "referenced", (i.e. required by the application), then they will "survive" the Garbage Collection process. Objects that "survive" Garbage Collection are promoted to the Survivor Space, and objects that remain referenced in the Survivor Space will be promoted to the Old Generation. This is a simplification of the process, and often objects will only be promoted after surviving multiple collections, but a basic illustration of the collection and promotion process is illustrated below:
.
In order to perform in the most efficient manner possible, Garbage Collection processes run in three different stages, (Minor, Major, and Full), to take full advantage of the generational architecture of the Heap's memory.
GC Collection Types
Minor GC cleans dead objects from the Eden and Survivor spaces and promotes objects that survive.
Major GC cleans dead objects from the Tenured space.
Full GC cleans dead objects from the entire Heap, (both Eden and Tenured spaces), and defragments the memory space.
Objects Die Young
An important concept in the Garbage Collection process is that most objects "die young", that is they are only referenced for a short period of time and therefore will not survive long enough to be promoted from the Eden Generation. Therefore the most common type of collection process is a Minor GC, which cleans dead objects from the Eden and Survivor spaces, and promotes surviving objects to the Tenured space. The Major GC process will run less frequently, because the Tenured space is usually much larger than the Eden and Survivor spaces, and if all is well with the memory management then a Full GC will be a rare occurrence.
The survival rate of objects is highly dependent on the application and its usage, but an illustration of the object life cycle is included below:
.
.
Garbage Collection and Stop The World
"Stop The World", (STW), means that the JVM is stopping the application from running processes to execute the Garbage Collection process. When a stop-the-world pause occurs, every thread except for the threads needed for the GC will stop running their task, the GC process will clean up the dead objects and then the interrupted tasks will pause and resume seamlessly. "Stop The World" collections will occur no matter which GC algorithm you choose, but some collectors will cause this to happen less often than others and GC tuning often seeks to reduce the STW pause time. The various collector algorithms are discussed below:
Garbage Collection Algorithms
Throughput collectors run in a Serial, (single thread), or Parallel, (multiple threads), configuration and are designed to achieve the maximum "throughput", (application run time vs STW pauses). They run in bursts, pausing the application threads and collecting dead objects, then stopping the GC process again to allow the maximum amount of system resources to be dedicated to the application.
Concurrent collectors are designed for applications that prefer shorter garbage collection pauses and that can afford to share processor resources with the garbage collector while the application is running. They run "concurrently" with the application, and only perform Stop The World collections when necessary, but this trades system resources that would be otherwise allocated to the application.
G1GC collector is a hybrid of throughput and concurrent collectors, which is used for large heap memory areas. It separates the heap memory into regions and does collection within them in parallel. G1 also compacts the free heap space on the fly, just after reclaiming the memory, which helps reduce the Heap fragmentation and the need for the G1GC collector to perform Full GCs. The concurrent collectors only compact the memory on Stop The World (STW) pauses, whereas the G1 collector is more advanced and prioritizes the region to be collected based on most garbage first, which helps reduce the STW pause times and also reduces the likelihood of the collector ever needing to do a Full GC.
Heap Fragmentation
One issue with the way that the Garbage Collection process collects from the Heap is that objects are stored contiguously when allocated and then removed from the Heap Memory when they die, which can lead to fragmentation of the Heap Memory over time. Generally, fragmentation doesn't have a big impact on the functionality of the application, but in rare cases, it can cause a Full GC process to trigger unexpectedly, (only Full GC will "Compact" the heap), so Heap fragmentation is always worth mentioning when discussing Java memory management. An illustration of the nature of fragmentation is included below:
.
.
Memory Speed/Quality
Due to the nature of Java memory management processes and Garbage Collection, it is vitally important that the memory used by the Java application is as fast as possible for optimal performance. Swapping, (use of disk memory), is especially disastrous with JVM processes. The JVM generally won't do a Major/Full GC cycle until it has run out of its allocated heap, so it's common that large sections of the Heap are occupied by not-yet-collected garbage. Since these pages aren't being touched (because they contain "garbage" and are thus no longer referenced), the OS happily swaps them out to disk leading to extended periods of Garbage Collection whilst the pages are swapped back into memory before being processed by the GC process.
| Many Linux distributions have an "Out Of Memory Killer", which will trigger when the kernel decides it has spent a "significant" amount of time scanning memory for something to free. This can be a common occurrence when unreferenced "garbage" gets swapped out and then collected |
Contiguous Memory Addresses
By default the Operating System kernel will use small blocks of memory, allocated as required, and then map those to appear to create contiguous memory space for the application. However, this process relies on Virtual Memory addressing, which maps virtual memory addresses to physical memory addresses and relies on a Translation Lookaside Buffer to speed up the conversion process. This process can be avoided by configuring Explicit Huge Pages memory pages and memory locking to ensure a contiguous memory space for the application to work with. You can read more about this in our knowledge base article on the subject: https://www.fredhopper.com/learningcenter/x/TRxwAQ
Comments
0 comments
Please sign in to leave a comment.