3. Web/Mobile Developer since the late 1990s
Interested in: Java, CFML, Functional
Programming, Go, JS, Mobile, Raspberry Pi
!
I’ve already showed you where I live :)
Me
4. - The JVM and Java Memory Management
- What’s the big deal with Garbage Collection?
- GC Strategies for various situations & JVMs
- How to approach JVM “tuning”?
- CFML specifics
Agenda
8. History
First JVM implementations were rather simple:
- Weak JMM (Java Memory Model)
- Issues with concepts like final, volatile etc.
-Very simple, non-generational memory
- “Mark-and-Sweep” Garbage Collection
!
9. History
Hotspot JVM was introduced in Java 1.2 as an
add-on — became part of the default setup in
Java 1.3 (~ mid 2000).
!
Also be aware of notational flukes:
1.0 -> 1.1 -> Java 2 (1.2) -> Java 2 (1.3) -> Java 2
(1.4) -> Java 5 -> Java 6 -> Java 7 -> Java 8
13. JVM Garbage
Over time the JVM accumulates a lot of objects
that are not needed anymore.
If we didn’t clean up, we’d get Out-Of-Memory
errors sooner or later.
Q:What’s being cleaned up?
A:“Dead” objects
!
14. JVM Garbage Collection
Every single GC algorithm starts with some kind
of “marking”: identifying the objects that are not
necessary anymore.
The Collector would start with a Root Set and
follow along object references it can reach.
Everything else is Garbage and can go!
Q:What’s the Root Set?
15. The Root Set
References on the Call Stacks of the JVM’s
threads
Global References, e.g. static fields in Classes
!
The Root Set are entry points into the reference
graph of “alive” objects.
!
20. Root Set and Reference Graphs
What we’ve looked at is a basic “Mark-and-
Sweep” algorithm.
The “Free List” could in the easiest form just be
used to mark memory as free.
Problem: Fragmentation and therefore inability
to assign memory for new, fresh objects.
!
23. Basics of Generational Memory: Heap
Stores your objects and classes at the JVM’s
runtime.
Usually the following basic assumptions are true:
- Lots of short-lived objects
-Very few (or: fewer) long-lived objects
Also function-local objects are created here.
25. Heap management
The JVM can’t know in advance what the lifespan
of a certain object would be.
Generational Memory Management is a solution
to overcome this issue and fragmentation:
-Young Generation
- Old Generation / Tenured Generation
- Permanent Generation (special case…)
27. Young Generation - for new objects
!
!
Typical short-lived objects:
- Objects local to a function
- Loop iterators, StringBuilders etc.
!
28. Young Generation - for new objects
!
!
Typical medium-lived objects:
- Objects tied to a session
!
!
29. Young Generation - for new objects
!
!
Typical long-lived objects:
- Thread Pools
- Singletons
- Certain framework objects
30. Young Generation - what happens next?
In general and following the theory of
Generational Memory Management:
-YG fills up -> Garbage Collection happens
-YG collection is supposed to be fast
If an object survives a certain amount of
collections in theYG, the JVM will assume the
object is medium- or long-lived and move it into
the Old Generation.
31. Old Generation
Over time, more long-lived objects end up in the
Old Generation and at some point it’s going to
be full.
In general and following the theory of
Generational Memory Management:
- OG fills up -> Garbage Collection happens
- OG collection is usually slower thanYG
- Size of OG
32. Why is Generational Memory good?
Lots of garbage - cleaning it up fast is worthwhile
Generational Memory Management:
-YG GC often -> space for new objects
- Each generation focusses on “type” of objects
- GC doesn’t have to search the whole heap
!
!
33. Permanent Generation
Not a “Generation” as such, but still needs to be
managed appropriately.
Stores:
- Classes
- Internal JVM objects
- JIT information
!
36. Young Generation Strategies
Generally, theYG is smaller than the OG.
TheYG consists of sub-sections:
- Eden (new objects)
- Survivor 1 and Survivor 2
One Survivor space is always empty and during a
YG collection the JVM will copy survivors from
Eden and S1 to S2 and vice versa.
37. Old Generation Strategies
The amount of survived GCs in theYG is called
“Tenuring Threshold”
If Eden and Survivor Spaces are too small,
sometimes objects might get instant-promoted
to the OG (because there’s no space in theYG).
Old Generation Collections are usually
expensive (slow, long)!
!
41. Ergonomics
Since Java 5 (and much improved in Java 6-land),
the JVM comes pre-setup with certain criteria
for selecting GC strategies and settings
(“Ergonomics”). Most can be changed.
!
!
JRockit/Apple JVMs — similar mechanisms
!
44. YG Collectors: Serial
Mark-and-Copy: Marking phase gets all reachable
objects, Copy moves those into a new (empty)
space.
Problems:
- Slightly more expensive than MaS
- Copying and References have to be shifted
- “Intergenerational References” -> homework
45. YG Collectors: Serial
Both MaS and MaC need exclusive access to the
Reference Graph.
Stop-the-World: stops all threads, the collection
was traditionally done by a single “Reaper
Thread”.
Problems:
- Long Pauses
- Inefficient
46. YG Collectors: Parallel
Parallel MaC (since Java 1.4.2) distributes the
Marking and Copying phases over multiple
threads.
The actual collecting is still Stop-the-World, but
for a much shorter period of time.
YG default since Java 5 if machine has 2+ cores
or CPUs, otherwise: -XX:+UseParallelGC
!
49. OG Collectors
Many objects and low mortality means MaC
would be inefficient. Instead we use Mark-and-
Compact.
MaCo is a variation of MaS with lower
fragmentation
4 Phases: Marking, Calculation of new Locations,
Reference Adjustments and Moving
!
50. OG Collectors
MaCo is a Full Collection algorithm - there’s no
“Pure OG collection”.
Doesn’t run often, but if it runs it’ll take a while.
Performance issues:
- All objects are visited multiple times
- Serial collector, stops all the threads
Enable via -XX:+UseSerialGC
51. OG Collectors: parallel
ParallelOld: Parallel and more efficient version of
MaCo, still Stop-the-World though - but shorter
StW pause than MaCo.
Idea:
- Marking and Compacting are multi-threaded
- Algorithm operates on 2 segments per thread
OG default since Java 6 on server profiles or via
-XX:+UseParallelOldGC
52. OG Collectors: concurrent
CMS: concurrent version of MaS, does NOT
need to stop threads for the majority parts of its
work.
4 Phases: Initial Marking, Concurrent Marking,
Remarking, Concurrent Sweep.
Stop-the-World: Initial Marking & Remarking
CMS via -XX:+UseConcMarkSweepGC
!
53. OG Collectors: concurrent
Concurrent Mark-and-Sweep is the preferred
OG collector if you want to minimise Stop-the-
World collections.
Overall throughput slightly less than ParallelOld,
but much better suited for web/server apps.
Well suited for large heaps (but be aware of
fragmentation), there’s an “incremental” mode
for systems with 1-2 cores.
54. OG Collectors: G1 (Garbage First)
G1 is a replacement for CMS (experimental in
later Java 6 release, full support in Java 7+)
Benefits:
- Low-pause
- Adaptable
- Much less fragmentation than CMS
- Better collector for full heap
55. OG Collectors: G1 (Garbage First)
Heap is split into regions (1-32MB)
Collector is controlled by min time between GC
pauses and min length of GC pause
!
!
In Java 6/7 (6u14, 7u4) set via -XX:+UseG1GC
!
58. Preamble
Do not trust consultants, blog posts, mailing list
discussions etc. telling you what the “best” JVM
settings for you would be.
(That’s including myself!)
There is no such thing as the “best” settings.
It solely depends on the application and your
usage.
59. Typical reasons for tuning
Application Growth
Change in available Resources (memory, CPU
etc)
Actual Performance issues (unresponsiveness…)
JVM-level error messages in log files
65. GC tuning results/criteria
More often than not you’d want to optimise for
low GC pauses.
!
GC Throughput: 95%+ are good.
Optimising for Throughput usually leads to
longer GC pauses, still useful for batch
operations.
66. Memory sizing concerns
Initial and maximum heap size:
-Xms4096m, -Xmx6144m
PermGen size:
-XX:MaxPermSize=256m
YG size:
-XX:NewSize=768m, -XX:MaxNewSize=768m
67. Memory sizing concerns
32bit JVM: theoretically 4GB
- In reality under Windows: ~1.2-1.4GB
Switching to a 64bit JVM creates ~20-30%
memory overhead due to longer pointer
references.
Also: easier to multi-threaded create new
objects than clean them up multi-threaded.
68. Example
Setup of extremely high volume/traffic site,
optimisation goal low pause times
-Xms6144m -Xmx6144m
-XX:NewSize=2500m -XX:MaxNewSize=2500m
-XX:+CMSIncrementalMode
-XX:+ExplicitGCInvokesConcurrent
-XX:+CMSPermGenSweepingEnabled
-XX:+CMSClassUnloadingEnabled
-XX:MaxPermSize=384m
-XX:PermSize=384m
-XX:+UseConcMarkSweepGC
69. Overview Java 6
Max throughput Min pause time
2+ cores 1 core 2+ cores 1 core
YG parYG serYG parYG parYG
OldGen par OG ser OG CMS iCMS
JVM Flags defaults
-XX:
+UseSerialGC
-XX:
+UseConcMarkSweepGC
(implicitly using: -XX:
+UseParNewGC forYG)
-XX:
+UseConcMarkSweepGC
-XX:
+CMSIncrementalMode
(implicitly using: -XX:
+UseParNewGC forYG)
70. Overview Java 7
Max throughput Min pause time
2+ cores 1 core 2+ cores 1 core
YG parYG serYG G1 parYG
OldGen par OG ser OG G1 iCMS
JVM Flags defaults
-XX:
+UseSerialGC
-XX:+UseG1GC
-XX:
+UseConcMarkSweepGC
-XX:
+CMSIncrementalMode
(implicitly using: -XX:
+UseParNewGC forYG)
(Oracle Java 7 JVMs also incorporate some JRockit features)