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
Name JVM Flag Young Collector Old Collector
Serial GC -XX:+UseSerialGC DefNew SerialOld
Parallel -XX:+UseParallelGC ParallelScavenge ParallelOld
Parallel Old -XX:+UseParallelOldGC ParallelScavenge ParallelOld
Parallel New -XX:+UseParNewGC ParNew SerialOld
Concurrent Mark Sweep -XX:+UseConcMarkSweepGC ParNew ConcurrentMarkSweep
Garbage First -XX:+UseG1GC G1New G1Old

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
Flag Description
-XX:+PrintGC Print messages at garbage collection
-XX:+PrintGCDetails Print more details at garbage collection
-XX:+PrintGCTimeStamps Print timestamps at garbage collection
-XX:+PrintGCApplicationStoppedTime Print the application GC stopped time
-XX:+PrintGCApplicationConcurrentTime Print 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
Flag Description
-XX:+UseGCLogFileRotation Enable GC log rotation
-XX:NumberOfGCLogFiles=n Set the number of files to use when rotating logs, must be >= 1. Eg: -XX:NumberOfGClogFiles=100
-XX:GCLogFileSize=size The 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

Jim Taylor said…
Good article. Got a lot of information. About analyzing GC logs, Analyse GC Logs is also good. It is free web tool. You have to upload your GC logs to their server, and results are provided online.

Popular posts from this blog

Specifying a custom Event Settings file for Java Flight Recorder

Flame Graphs with Java Flight Recordings

Benchmarking Java Locks with Counters