Skip to main content

Java Garbage Collection

In this blog post, I'm briefly introducing important concepts in Java Garbage Collection (GC) and how to do GC Logging. There are many resources available online for Java GC and I'm linking some of those in this post.

Why Garbage Collection is important?


When we develop and run Java applications, we know that Java automatically allocates memory for our applications. Java also automatically deallocates memory when certain objects are no longer used. As Java Developers, we don't have to worry about memory allocations/deallocations as Java takes care of the task to manage memory for us.

This memory management is a part of "Automatic Garbage Collection", which is an important feature in Java.  It is important to know how Garbage Collection manages memory in our programs.

See Java Garbage Collection Basics, which is a great "Oracle by Example (OBE)" tutorial to understand the basics in Java GC.

See also Java Garbage Collection DistilledWhat is Garbage Collection?Java Garbage Collection IntroductionJVM performance optimization, Part 3: Garbage collection and the whitepaper on Memory Management in the Java HotSpot� Virtual Machine

Java GC is also an important component when tuning performance of the JVM.

Marking and Sweeping Away Garbage


GC works by first marking all used objects in the heap and then deleting unused objects. This is called a mark-and-sweep algorithm.

GC also compacts the memory after deleting unreferenced objects to make new memory allocations much easier and faster.

JVM references GC roots, which refer the application objects in a tree structure. There are several kinds of GC Roots in Java.

  1. Local Variables
  2. Active Java Threads
  3. Static variables
  4. JNI references
When the application can reach these GC roots, the whole tree is reachable and GC can determine which objects are the live objects.

Java Heap Structure


Java Heap is divided in to generations based on the object lifetime. This allows the GC to perform faster as the GC can mark and compact objects in particular generation. Usually in Java applications, there are many short lived objects and there will be less objects remaining in the heap for a long time. 

Following is the general structure of the Java Heap. (This is mostly dependent on the type of collector).

Java Memory

There are three Heap parts.
  1. Young Generation
  2. Old Generation
  3. Permanent Generation

We can define the heap sizes with JVM arguments. See Java Non-Standard Options.

Following are some common arguments.
  • -Xms - Initial heap size
  • -Xmx - Maximum heap size
  • -Xmn - Young Generation size
  • -XX:PermSize - Initial Permanent Generation size
  • -XX:MaxPermSize - Maximum Permanent Generation size

Young Generation


Young Generation usually has Eden and Survivor spaces.

All new objects are allocated in Eden Space. When this fills up, a minor GC happens. Surviving objects are first moved to survivor spaces. When objects survives several minor GCs (tenuring threshold), the relevant objects are eventually moved to the old generation based on the age.

Old Generation


This stores long surviving objects. When this fills up, a major GC (full GC) happens. A major GC takes a longer time as it has to check all live objects.

Permanent Generation


This has the metadata required by JVM. Classes and Methods are stored here. This space is included in a full GC.

In Java 8, the PermGen is removed.

"Stop the World"


When certain GC happens, all application threads are stopped until the GC operation completes. These kind of GC events are called as "Stop the World" events/pauses.

When GC tuning, one of the main targets is to reduce the time for "Stop the World" pause.

Java Garbage Collectors


Following are some garbage collectors available in Java 7 and there are different scenarios to use those. See Java Garbage Collectors in OBE tutorial, Types of Java Garbage CollectorsGarbage Collection in Java (1) - Heap Overview and Understanding Java Garbage Collection.

  1. The Serial GC
  2. The Parallel Scavenge (PS) Collector
  3. The Concurrent Mark Sweep (CMS) Collector
  4. The Garbage First (G1) Collector
See Java HotSpot VM Options for specific flags to enable above collectors.

My test runs revealed that the Parallel GC and the Parallel Old GC flags activate the Parallel Scavenge Collector (Java 1.7.0_80).

Following are some of my observations when using different collectors with Java 7 (I got the Young & Old Garbage Collectors from the GC configuration tab after opening a Java Flight Recording in Java Mission Control).


Garbage Collectors
NameJVM FlagYoung CollectorOld Collector
Serial GC-XX:+UseSerialGCDefNewSerialOld
Parallel-XX:+UseParallelGCParallelScavengeParallelOld
Parallel Old-XX:+UseParallelOldGCParallelScavengeParallelOld
Parallel New-XX:+UseParNewGCParNewSerialOld
Concurrent Mark Sweep-XX:+UseConcMarkSweepGCParNewConcurrentMarkSweep
Garbage First-XX:+UseG1GCG1NewG1Old

JVM GC Tuning Guides


See following:

System.gc()


A GC can be triggered by calling System.gc() from a Java program. However, a call to System.gc() does not guarantee that the system will a run a GC.

Using this method is not recommended and we should let the JVM to run GC whenever needed.

The finalize() method


An object's finalize() method is called during GC. We can override the finalize method to clean up any resources. 

GC Logging


There are JVM flags to log details for each GC. See Useful JVM Flags � Part 8 (GC Logging)

See Understanding Garbage Collection Logs.

Following are some important ones. Last two flags log the Application times


GC Logging Flags
FlagDescription
-XX:+PrintGCPrint messages at garbage collection
-XX:+PrintGCDetailsPrint more details at garbage collection
-XX:+PrintGCTimeStampsPrint timestamps at garbage collection
-XX:+PrintGCApplicationStoppedTimePrint the application GC stopped time
-XX:+PrintGCApplicationConcurrentTimePrint the application GC concurrent time

Note: "-verbose:gc" is same as "-XX:+PrintGC".

The "-Xloggc:" flag can be used to output all GC logging to a file instead of standard output (console).

Following flags can be used with "-Xloggc" for log rotation.

GC Log File Flags to be used with -Xloggc
FlagDescription
-XX:+UseGCLogFileRotationEnable GC log rotation
-XX:NumberOfGCLogFiles=nSet the number of files to use when rotating logs, must be >= 1. Eg: -XX:NumberOfGClogFiles=100
-XX:GCLogFileSize=sizeThe size of the log file at which point the log will be rotated, must be >= 8K. Eg: -XX:GCLogFileSize=8K


Note: Evan Jones has found that JVM statistics cause garbage collection pauses.


Viewing GC Logs


The GCViewer is a great tool to view GC logs created from above mentioned flags.


GCViewer

Summary


This blog post briefly introduced Java Garbage Collection, Java Heap Structure, Different Type of Garbage Collectors and how to do GC logging. I strongly recommend to go through the links and read. Those resources have much more details and this blog post is just a summarized post on Java GC.

Some resources have outdated information and it's better to run some sample programs and try out.

I used sample Java2D demo as explained in OBE tutorial to test different garbage collectors. If you used my Java Installation Script, all Java demos will be installed inside $JAVA_HOME/demo.

Following are some example commands I used.


#Default Collector
$JAVA_HOME/bin/java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Xmx20m -Xms3m -XX:PermSize=20m -XX:MaxPermSize=40m -jar $JAVA_HOME/demo/jfc/Java2D/Java2Demo.jar
#Serial GC
$JAVA_HOME/bin/java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Xmx20m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=40m -XX:+UseSerialGC -jar $JAVA_HOME/demo/jfc/Java2D/Java2Demo.jar
#Parallel GC
$JAVA_HOME/bin/java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Xmx20m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=40m -XX:+UseParallelGC -jar $JAVA_HOME/demo/jfc/Java2D/Java2Demo.jar
#Parallel Old GC
$JAVA_HOME/bin/java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Xmx20m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=40m -XX:+UseParallelOldGC -jar $JAVA_HOME/demo/jfc/Java2D/Java2Demo.jar
#Concurrent Mark Sweep GC
$JAVA_HOME/bin/java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Xmx20m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=40m -XX:+UseConcMarkSweepGC -jar $JAVA_HOME/demo/jfc/Java2D/Java2Demo.jar
#Parallel New GC
$JAVA_HOME/bin/java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Xmx20m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=40m -XX:+UseParNewGC -jar $JAVA_HOME/demo/jfc/Java2D/Java2Demo.jar
#Garbage First (G1) collector
$JAVA_HOME/bin/java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -Xmx20m -Xms3m -XX:+UseG1GC -jar $JAVA_HOME/demo/jfc/Java2D/Java2Demo.jar

#GC Logging
#-XX:+PrintGCDetails -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=100 -XX:GCLogFileSize=1024K




Comments

Popular posts from this blog

Finding how many processors

I wanted to find out the processor details in my laptop and I found out that there are several ways to check. For example, see The RedHat community discussion on  Figuring out CPUs and Sockets . In this blog post, I'm listing few commands to find out details about CPUs. I'm using Ubuntu in my Lenovo ThinkPad T530 laptop and following commands should be working any Linux system. Display information about CPU architecture $ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 58 Model name: Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz Stepping: 9 CPU MHz: 1199.988 CPU max MHz: 3600.0000 CPU min MHz: 1200.0000 BogoMIPS: 5787.1...

Java Mission Control & Java Flight Recorder

Last year, I got two opportunities to talk about Java Mission Control & Java Flight Recorder. I first talked about " Using Java Mission Control & Java Flight Recorder " as an internal tech talk at WSO2 . I must thank Srinath for giving me that opportunity. After that, Prabath also invited me to do a talk at Java Colombo Meetup . Prabath, Thank you for inviting me and giving me the opportunity to talk at the Java Colombo Meetup! I'm also very excited to see that Marcus Hirt , the Team Lead for Java Mission Control has mentioned about the Java Colombo Meetup in his blog post: " My Favourite JMC Quotes ". It's so nice to see "Sri Lanka" was mentioned in his blog post! :) From Marcus' Blog Here are the slides used at the meetup. Java Colombo Meetup: Java Mission Control & Java Flight Recorder from Isuru Perera Marcus Hirt's blog posts really helped me to understand JMC & JFR concepts and his tutorials were very helpful...

Flame Graphs with Java Flight Recordings

Flame Graphs Brendon D. Gregg , who is a computer performance analyst , has created  Flame Graphs to visualize stack traces in an interactive way. You must watch his talk at USENIX/LISA13 , titled Blazing Performance with Flame Graphs , which explains Flame Graphs in detail. There can be different types of flame graphs and I'm focusing on  CPU Flame Graphs  with Java in this blog post. Please look at the Flame Graphs Description  to understand the Flame Graph visualization. CPU Flame Graphs and Java Stack Traces As  Brendon  mentioned in his talk, understanding why CPUs are busy is very important when analyzing performance.  CPU Flame Graphs  is a good way to identify hot methods from sampled stack traces. In order to generate CPU Flame Graphs for Java Stack Traces , we need a way to get sample stack traces. Brendon has given examples to use jstack  and Google's lightweight-java-profiler . Please refer to his perl program on g...