Garbage Collectors
Alonso Torres @alotor
Someone
“I know”
(definitely not me)
java.lang.OutOfMemoryError: unable to create new native thread
java.lang.OutOfMemoryError: Stack overflow
java.lang.OutOfMemoryError: PermGen space
java.lang.OutOfMemoryError: Metaspace
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: requested... Out of swap space?
DONE!!
Java needs lots of memory!!!
Java is so slow!!!!!!
Garbage collection is
wrong!!!!!
With CMS GC, the full collection is serial and STW,
hence your application threads are stopped for the
entire duration while the heap space is reclaimed
and then compacted.
The duration for the STW pause depends on your
heap size and the surviving objects.
http://www.infoq.com/articles/G1-One-Garbage-Collector-To-Rule-Them-All
With CMS GC, the full collection is serial and STW,
hence your application threads are stopped for the
entire duration while the heap space is reclaimed
and then compacted.
The duration for the STW pause depends on your
heap size and the surviving objects.
http://www.infoq.com/articles/G1-One-Garbage-Collector-To-Rule-Them-All
Garbage Collectors
WTF?!
Why They Fail?!
Alonso Torres
@alotor
1. Structure of JVM’s memory
2. Concepts about Garbage Collection
3. Types of collectors in Oracle’s Hotspot
4. Configurations inside JVM about GC
Introducing
JVM
JVM PROCESS
JVM PROCESS
JVM PROCESS
Stack
- Execution memory
- Per-thread
- Stack limit (call depth before stack overflow)
● Java 7 ~ 10,000
● Java 8 ~ 20,000
JVM PROCESS
Permgen vs Metaspace
- Store information about classes
- Java <= 7 Permgen is part of the heap
- Java >= 8 Metaspace is native memory
JVM PROCESS
HEAP
- Reserved block of memory that the JVM will be in
charge of managing
- Stores object’s data
- Dynamic memory
JVM PROCESS
FREEUSED
Max. Heap Size
FREEUSED
Max. Heap Size
FREEUSED
Max. Heap Size
FREEUSED
Max. Heap Size
LIBREUSED
Max. Heap Size
GROW the heap
or
FREE memory
USED FREE
USED FREE
Grow the heap
Free the heap
How do we free the memory that
we don’t need anymore?
1. Searches for objects that are alive
2. Frees memory used by dead objects
3. Reallocates memory for alive objects
Garbage Collection
- Serial Collector
- Parallel Collector
- CMS Collector
- G1
GC’s en OpenJDK Hotspot
- Serial Collector
- Parallel Collector
- CMS Collector
- G1
GC’s en OpenJDK Hotspot
DAMN YOU
CONCEPTS!!
- Most objects die young
- Old objects, normally, don’t reference younger
ones
Weak Generational Hypothesis
Two kind of collection:
○ 1 small space with lots of deads
○ 1 big space mostly objects alive
Generational GC
DeathRate
Age
DeathRate
Age
Every JVM
Garbage Collector
is generational
YOUNG OLD/TENURE
Generational heap structure
S
U
R
V
I
V
O
R
S
OLD/TENUREEDEN
Generational heap structure
S
U
R
V
I
V
O
R
S
Collect the young generation
Collect the young generation
Promoted objects go to the survivors space and to
the old generation
The old generation is full
We need a full collection
Empty young and survivors.
Free dead old-gen objects
Only currently alive objects
Characteristics of GC
Concurrent
Parallel
Incremental
STW
Serial
Monolithic
- Global stop of every thread to execute a
garbage collection
- The opposite would be CONCURRENT
○ GC executed at the same time as the
program
Stop the World (STW)
STW Concurrent
● GC executed in several threads
● Will leverage multi-core processors
● The opposite would be SERIAL
○ Only one thread for the GC
Parallel
Parallel Serial
● Collection in several phases or steps
● Steps/phases can be of different types
● Opposite is: MONOLITHIC
○ Everything in one go
Incremental
Incremental Monolithic
Characteristics of GC
Concurrent
Parallel
Incremental
STW
Serial
Monolithic
Parallel Concurrent
Latency
Maximum time the application is stopped doing GC
Throughput
Percentage of time not dedicated to GC
Latency and throughput
15
seconds
5
seconds
30
seconds
Throughput: 90%
15 + 5 + 30 = 100%
15 + 30 = T
T = (50 / 45) * 100
= 90%
Latency: 5 seconds
● Serial Collector
● Parallel Collector
● CMS Collector
● G1 (Garbage First) Collector
GC’s in OpenJDK Hotspot
YOUNG GENERATION OLD GENERATION
Serial
Monolithic
STW
Copying Mark / Sweep / Compact
Serial Collector
- Copies the alive objects from one memory
region to another
- Frees the source memory zone (moves)
Copying algorithm (Scavenge)
1. Mark
Mark / Sweep / Compact (MSC)
2. Sweep
Mark / Sweep / Compact (MSC)
3. Compact
Mark / Sweep / Compact (MSC)
● Serial Collector
● Parallel Collector
● CMS Collector
● G1 (Garbage First) Collector
GC’s en OpenJDK Hotspot
Parallel Collector
YOUNG GENERATION OLD GENERATION
Parallel Serial / Parallel
Monolithic
STW
Copying Mark / Sweep / Compact
Parallel collector
maximize throughput
● Serial Collector
● Parallel Collector
● CMS Collector
● G1 (Garbage First) Collector
GC’s en OpenJDK Hotspot
YOUNG GENERATION OLD GENERATION
Parallel Serial + Parallel
Monolithic Incremental
STW STW + Concurrent
Copying Mark and Sweep
Concurrent Mark & Sweep
1. Initial Mark
2. Concurrent Mark
3. Remark
4. Concurrent Sweep
Concurrent Mark & Sweep
CMS
minimize latency pause
but
does NOT compact
CMS after several collections
STW, Serial, Monolithic, MSC*
*AKA: Full GC
When there is excessive
fragmentation
● Serial Collector
● Parallel Collector
● CMS Collector
● G1 (Garbage First) Collector
GC’s en OpenJDK Hotspot
- Delay as much as possible a “Full GC”
- Low latency
- Predictability
- Easy to use
Garbage First (G1)
- Divides the heap in regions
- 2048 regions. Size: heap / 2048 ~ nearest factor of 2
- Frees first the regions with more garbage
(Garbage First)
- Compacts while moving
Garbage First (G1)
G1 Heap Structure
E O
O
E
O
O
O
S
G1 Heap Structure
E
1. Collects the Young Generation
2. Concurrent marking
3. Mixed collection
4. Evacuation failure
Garbage First (G1)
E O
O
E
O
O
O
E
Young collection
E
Young collection
E O
O
E E
O
O
O
E
Young collection
O
O
O
O
O
S
1. Collects the Young Generation
2. Concurrent marking
3. Mixed collection
4. Evacuation failure
Garbage First (G1)
Concurrent marking
E O
O
O
O
O
E
O
O O
E S
Concurrent marking
E O
O
E
X
O
X
O
O O
O
1. Collects the Young Generation
2. Concurrent marking
3. Mixed collection
4. Evacuation failure
Garbage First (G1)
Mixed collection
E O
O
E
E X
O
X
E
O
O O
O
O
O
O
O
Mixed collection
E O
O
E
E X
O
X
E
O
O O
O
O
O
O
O
Mixed collection
O
O
O
X
O
O O
O
O
O
O
OS
1. Collects the Young Generation
2. Concurrent marking
3. Mixed collection
4. Evacuation failure
Garbage First (G1)
Evacuation failure
O
O
O
O
O O
O
O
O
O
S O
O
O
O
O
O
O O
O
OO O
O
O
O
O
O
O
O
O
OO
E
E
E
Not enough space for collect the young or
survivors. What happens then?
Full GC
STW, Serial, Monolithic, MSC
All the GCs in Oracle’s JVM
eventually Stop The World
Special treatment for “huge” objects
- Objects > 50% region size
- Special Humongous region
- Not moved between regions: More fagmentation!
- If using G1 try to avoid huge objects
G1 - Humongous objects
Humongous collection
H
O
O
X
O
O O
O
O
O
O
OS
- Region Size = Heap Size / 2048
- Humongous Threshold = Region Size / 2
If your Heap is very small, every object can
become humongous!
G1 - Humongous objects
CMS vs G1
CMS vs G1
Minimize duration of STW Minimize quantity of STW
Throughput Latency
Old New-ish
Better for small heaps The best for large heaps
Fragmentation Compacts
CMS vs G1
Bottom line:
- G1 is the new default GC for Java 9
- Long term replacement for the CMS
If you want throughput Parallel GC it’s better
JVM configuration
Maximum Heap Size
- Big heap long STW pauses
- Small heap lots of small pauses
-Xms512m -Xmx8g
Max. Heap SizeInitial Heap Size
Choose your poison
Serial
Parallel
CMS
G1
-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseConcMarkSweepGC
-XX:+UseG1GC
java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=191892544
-XX:MaxHeapSize=3070280704
-XX:+PrintCommandLineFlags
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:+UseParallelGC
docker run -it java:9 java -XX:+PrintCommandLineFlags -version
-XX:G1ConcRefinementThreads=4
-XX:InitialHeapSize=191892544
-XX:MaxHeapSize=3070280704
-XX:+PrintCommandLineFlags
-XX:ReservedCodeCacheSize=251658240
-XX:+SegmentedCodeCache
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:+UseG1GC
1. Never do premature optimization
2. Maximize young collection
3. Minimize STW
4. Avoid large objects
5. Minimize object retention
Optimization targets
and gather data
-Xloggc:<file>
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
GC Logs
[GC [PSYoungGen: 578424K->8793K(630784K)]
1007570K->444386K(1155072K), 0.0185270 secs]
[Times: user=0.06 sys=0.00, real=0.02 secs]
[GC [PSYoungGen: 580697K->15128K(636928K)]
1016290K->459169K(1161216K), 0.0236090 secs]
[Times: user=0.08 sys=0.01, real=0.02 secs]
[GC [PSYoungGen: 450179K->6893K(635904K)]
894221K->465458K(1160192K), 0.0249430 secs]
[Times: user=0.07 sys=0.02, real=0.02 secs]
[Full GC [PSYoungGen: 6893K->0K(635904K)]
[ParOldGen: 458564K->454236K(816128K)] 465458K->454236K(1452032K)
[PSPermGen: 171991K->171852K(344064K)], 2.5341620 secs]
[Times: user=8.48 sys=0.01, real=2.53 secs]
[GC [PSYoungGen: 578424K->8793K(630784K)]
1007570K->444386K(1155072K), 0.0185270 secs]
[Times: user=0.06 sys=0.00, real=0.02 secs]
[GC [PSYoungGen: 580697K->15128K(636928K)]
1016290K->459169K(1161216K), 0.0236090 secs]
[Times: user=0.08 sys=0.01, real=0.02 secs]
[GC [PSYoungGen: 450179K->6893K(635904K)]
894221K->465458K(1160192K), 0.0249430 secs]
[Times: user=0.07 sys=0.02, real=0.02 secs]
[Full GC [PSYoungGen: 6893K->0K(635904K)]
[ParOldGen: 458564K->454236K(816128K)] 465458K->454236K(1452032K)
[PSPermGen: 171991K->171852K(344064K)], 2.5341620 secs]
[Times: user=8.48 sys=0.01, real=2.53 secs]
Young Generation collection
Full GC (STW)
JConsole
YOUNG SURVIVORS OLD
Summary of the GC
JVisualVM
+
Visual GC plugin
JHiccup
https://github.com/giltene/jHiccup
Heuristic options
-XX:MaxGCPauseMillis=1000
-XX:GCTimeRatio=20
Limit the longest STW. Tries to maintain it on average
-XX:MaxGCPauseMillis=1000
-XX:GCTimeRatio=20
Application x20 more time than the GC
-XX:MaxGCPauseMillis=LATENCY
-XX:GCTimeRatio=T / (100 - T)
Change the generations
-XX:NewRatio=3
-XX:SurvivorRatio=8
-XX:MaxNewSize=1G
-XX:MaxTenuringThreshold=15
Ratio between the old and young generation is 1:3
-XX:NewRatio=3
-XX:SurvivorRatio=8
-XX:MaxNewSize=1G
-XX:MaxTenuringThreshold=15
Ratio between the eden and survivors 1:8
-XX:NewRatio=3
-XX:SurvivorRatio=8
-XX:MaxNewSize=1G
-XX:MaxTenuringThreshold=15
Absolute sizing of the young generation (eden + survivors)
-XX:NewRatio=3
-XX:SurvivorRatio=8
-XX:MaxNewSize=1G
-XX:MaxTenuringThreshold=15
Cycles that could live in the “survivors” space
G1 options
-XX:G1HeapRegionSize=n
-XX:G1NewSizePercent=5
-XX:G1MaxNewSizePercent=60
-XX:ParallelGCThreads=n
-XX:InitiatingHeapOccupancyPercent=45
Size of the regions
-XX:G1HeapRegionSize=n
-XX:G1NewSizePercent=5
-XX:G1MaxNewSizePercent=60
-XX:ParallelGCThreads=n
-XX:InitiatingHeapOccupancyPercent=45
Percentage of the regions dedicated to young generation (min/max)
-XX:G1HeapRegionSize=n
-XX:G1NewSizePercent=5
-XX:G1MaxNewSizePercent=60
-XX:ParallelGCThreads=n
-XX:InitiatingHeapOccupancyPercent=45
Number of threads for the collection
-XX:G1HeapRegionSize=n
-XX:G1NewSizePercent=5
-XX:G1MaxNewSizePercent=60
-XX:ParallelGCThreads=n
-XX:InitiatingHeapOccupancyPercent=45
Occupancy before starts a marking cycle
And many more….
http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html
java -XX:+PrintFlagsFinal -version | grep "G1.*s"
double G1ConcMarkStepDurationMillis = 10.000000 {product}
uintx G1ConcRSHotCardLimit = 4 {product}
uintx G1ConcRSLogCacheSize = 10 {product}
intx G1ConcRefinementGreenZone = 0 {product}
intx G1ConcRefinementRedZone = 0 {product}
intx G1ConcRefinementServiceIntervalMillis = 300 {product}
uintx G1ConcRefinementThreads = 0 {product}
intx G1ConcRefinementThresholdStep = 0 {product}
intx G1ConcRefinementYellowZone = 0 {product}
uintx G1ConfidencePercent = 50 {product}
uintx G1HeapRegionSize = 0 {product}
uintx G1HeapWastePercent = 5 {product}
uintx G1MixedGCCountTarget = 8 {product}
intx G1RSetRegionEntries = 0 {product}
uintx G1RSetScanBlockSize = 64 {product}
intx G1RSetSparseRegionEntries = 0 {product}
intx G1RSetUpdatingPauseTimePercent = 10 {product}
intx G1RefProcDrainInterval = 10 {product}
uintx G1ReservePercent = 10 {product}
uintx G1SATBBufferEnqueueingThresholdPercent = 60 {product}
intx G1SATBBufferSize = 1024 {product}
intx G1UpdateBufferSize = 256 {product}
bool G1UseAdaptiveConcRefinement = true {product}
bool UseG1GC = false {product}
1. Structure of JVM’s memory
2. Concepts about Garbage Collection
3. Types of collectors in Oracle’s Hotspot
4. Configurations inside JVM about GC
With CMS GC, the full collection is serial and STW,
hence your application threads are stopped for the
entire duration while the heap space is reclaimed
and then compacted.
The duration for the STW pause depends on your
heap size and the surviving objects.
http://www.infoq.com/articles/G1-One-Garbage-Collector-To-Rule-Them-All
Don't be afraid of the
big bad wolf
Alonso Torres
@alotor @alotor
REFERENCES
+ https://www.infoq.com/articles/G1-One-Garbage-Collector-To-Rule-Them-All
+ http://blog.takipi.com/garbage-collectors-serial-vs-parallel-vs-cms-vs-the-g1-and-whats-new-in-java-8/
+ http://blog.takipi.com/7-things-you-thought-you-knew-about-garbage-collection-and-are-totally-wrong/
+ http://blog.takipi.com/7-things-you-thought-you-knew-about-garbage-collection-and-are-totally-wrong/
+ http://blog.takipi.com/5-tips-for-reducing-your-java-garbage-collection-overhead/
+ https://adtmag.com/articles/2015/06/22/oracle-java-9.aspx
+ https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html
+ http://blog.mgm-tp.com/2013/12/benchmarking-g1-and-other-java-7-garbage-collectors/
+ http://www.petefreitag.com/articles/gctuning/
+ https://www.infoq.com/author/Monica-Beckwith
+ Java Performance. The Definitive Guide. By Scott Oaks (O'Reilly')
+ Viewer for the CG Logs: https://github.com/chewiebug/GCViewer

[Jbcn 2016] Garbage Collectors WTF!?