Hey Tea lovers! This post is about garbage collectors in Java. This is the continuation of the post series “Get Ready to Deep Dive Java Memory Management”. In Java memory management, a Garbage collector is the process by which Java programs perform automatic memory management. This is a more complicated process than just garbage collecting and freeing up memory.
The garbage collector is expensive to process which leads to a stop-the-world event.
Stop the World Event
- All the garbage collectors are “Stop the World” events because all application threads are paused until the operation completes.
- Since the Young generation keeps short-lived objects, Minor GC is very fast and the application doesn’t get affected by this.
- It will make your application unresponsive for the garbage collector duration. So if you have a responsive application and there are a lot of Major garbage collector happening, you will notice timeout errors.
- The duration taken by garbage collector depends on the strategy used for the garbage collector. That’s why it’s necessary to monitor and tune the garbage collector to avoid timeouts in the highly responsive applications.
Note: System.gc() and Runtime.gc() are the methods that request for Garbage collectors to JVM explicitly but it doesn’t ensure garbage collector as the final decision of garbage collector is of JVM only.
How it works
Depending on the type of reference that a variable from the stack holds to an object from the heap, at a certain point in time, that object reference is changed or removed then it becomes eligible for the garbage collector.
To go a bit deeper into the details, understand how the above object linking on heap & stack works as follows,
- Java code will run line by line manner.
- Every time if create any object it will store variable name on stack & object store on a heap with reference to it.
- As the above picture, we have an object in red & green
- Objects that are in green on the heap has strong references to other objects that are also on the heap & object red are eligible to be collected by the garbage collector.
- The garbage collector process is triggered automatically by Java, and it is up to Java when and whether or not to start this process.
- Reference from the stack is lost, it cannot be accessed anymore, so it will remove from the heap
Java Garbage Collector Types
There are five types of garbage collectors that we can use in our applications. We just need to use the JVM switch to enable the garbage collector strategy for the application.
Serial GC (-XX:+UseSerialGC)
- Uses the simple mark-sweep-compact approach for young and old generations garbage collector i.e Minor and Major GC.
- Useful in client machines such as our simple stand-alone applications and machines with smaller CPU. It is good for small applications with low memory usage.
Parallel GC (XX:+UseParallelGC)
- It is similar to serial GC except that, it spawns N (the number of CPU cores in the system) threads for the young generation garbage collector
- it uses multiple threads for both generations
- This GC type is also known as the throughput collector.
Parallel Old GC (-XX:+UseParallelOldGC)
- This is the same as Parallel GC except that it uses multiple threads for both young generation and old generation garbage collector
Concurrent Mark Sweep (CMS) Collector (-XX:+UseConcMarkSweepGC)
- CMS Collector is also referred to as a concurrent low pause collector.
- It does the garbage collector for the Old generation.
- CMS collector tries to minimize the pauses due to garbage collector by doing most of the garbage collector work concurrently with the application threads.
- CMS collector on the young generation uses the same algorithm as that of the parallel collector. This garbage collector is suitable for responsive applications where we can’t afford longer pause times.
- We can limit the number of threads in CMS collector using
- As of JDK 9, this GC type is deprecated.
G1 Garbage Collector (-XX:+UseG1GC)
- The Garbage First or G1 garbage collector is available from Java 7 and its long term goal is to replace the CMS collector.
- The G1 collector is a parallel, concurrent, and incrementally compacting low-pause garbage collector.
- Garbage First Collector doesn’t work like other collectors and there is no concept of Young and Old generation space. It divides the heap space into multiple equal-sized heap regions. When a garbage collector is invoked, it first collects the region with lesser live data, hence “Garbage First”.
- This considerably simplifies parts of the collector and mostly eliminates potential fragmentation issues. Also, G1 offers more predictable garbage collector pauses than the CMS collector and allows users to specify desired pause targets.
- In Java 8, the G1 collector comes with an amazing optimization which is known as String Deduplication. It enables the GC to identify strings that have multiple occurrences across the heap and modify them to point to the same internal char array so that there are no multiple copies in the heap. It can be enabled by using -XX:+UseStringDeduplication JVM argument.
- G1 is the default garbage collector in JDK 9.
Java Garbage Collector Tuning
Tuning should be the last option we use for increasing the throughput of the application and only when we see a drop in performance because of longer GC causing application timeouts.
Java provides a lot of memory switches that we can use to set the memory sizes and their ratios. Some of the commonly used memory switches are:
|VM Switch||VM Switch Description|
|-Xms||For setting the initial heap size when JVM starts|
|-Xmx||For setting the maximum heap size|
|-Xmn||For setting the size of the young generation, the rest of the space goes for the old generation|
|-XX:PermGen||For setting the initial size of the Permanent Generation Memory|
|-XX:MaxPermGen||For setting the maximum size of Perm Gen|
|-XX:SurvivorRatio||For providing a ratio of Eden space, for example, if the young generation size is 10m and VM switch is –XX:SurvivorRatio=2 then 5m will be reserved for Eden space and 2.5m each for both the Survivor spaces. The default value is 8|
|-XX:NewRatio||For providing a ratio of old/new generation sizes. The default value is 2|
|-XX:+UserSerialGC||For enable Serial garbage collector|
|-XX:+UseParallelGC||For enable a Parallel garbage collector|
|-XX:+UseConcmarkSweepGC||For enable CMS garbage collector|
|-XX:+ParallelCMSThreads=||For enabling CMS Collector as number of threads to use|
|-XX:+UseG1GC||For enable G1 garbage collector|
|-XX:HeapDumpOnOutOfMemory||pass a parameter to create a heap dump file when this error happens next time.|
check out more options here JVM Options Official Page.
Bonus Tips and Tricks
- Reuse objects where possible and avoid creating unnecessary objects
- Explicitly refer variables to null
- Use Phantom references for cleanup over finalizers
- Use StringBuilder instead of string concat operation
- Avoid initialization in the loop it takes up GC time
- Use primitives and avoid objects. (long instead of Long)
- Minimize the use of synchronization, it will apply an unnecessary lock
- JSPs are usually slower than servlets
- Perform updates and deletes in bulk
- Flush and clear out hibernate sessions periodically
- equals() is expensive if we are testing for an empty string. Use length property instead.
- “==” is faster than equals()
- n += 9 is faster than n = n + 9. fewer byte codes are generated in the first case
- To minimize memory use, limit the scope of the variables as much as possible. Remember that each time the top scope from the stack is popped up, the references from that scope are lost, and this could make objects eligible for garbage collecting.
- Do not use strong references where weak or soft references can use.
- Unless we have a problem with pauses, try granting as much memory as possible to the JVM
- Setting –Xms and –Xmx to the same value
- If a Java application crashes with an
OutOfMemoryErrorand you need some extra info to detect the leak, run the process with
–XX:HeapDumpOnOutOfMemoryparameter, which will create a heap dump file when this error happens next time.
- Don’t forget to tune the Perm Gen (only if you using java 7 or less)
- Use the
-verbose:gcoption to get the garbage collector output. Each time a garbage collector run, the output will be generated.
That’s it for this post. We have talked about the Garbage Collection in JVM. To learn more about the JVM architecture please visit the first part of this post “Get Ready to Deep Dive Java Memory Management: Structure of JVM“. In the next post, we will talk about the Java Memory tools in “Monitor Your Java Memory with these Tools“.
I hope you liked the post. I tried to simplify things. If I had missed something please feel free to suggest to me in the comment section. If you are still confused about the JVM, I would say please see my post series on JVM “Get Ready to Deep Dive Java Memory Management”. Please see them in the following order.
- Structure of JVM
- Garbage Collector
- Monitor Your Java Memory with these Tools
- A Day in the Life of Java Code in JVM
You can look at other posts such as Best practices in Java to improve your efficiency. See you in the next post.