Garbage Collection (aka Automatic Memory Management) Douglas Q. Hawkins. Why?

Similar documents
Java Performance Tuning

Fundamentals of GC Tuning. Charlie Hunt JVM & Performance Junkie

Garbage Collection. Hwansoo Han

JVM Memory Model and GC

Concurrent Garbage Collection

Lecture 13: Garbage Collection

Algorithms for Dynamic Memory Management (236780) Lecture 4. Lecturer: Erez Petrank

Attila Szegedi, Software

JVM Troubleshooting MOOC: Troubleshooting Memory Issues in Java Applications

Sustainable Memory Use Allocation & (Implicit) Deallocation (mostly in Java)

Contents. Created by: Raúl Castillo

Exploiting the Behavior of Generational Garbage Collector

Shenandoah An ultra-low pause time Garbage Collector for OpenJDK. Christine H. Flood Roman Kennke

THE TROUBLE WITH MEMORY

Runtime. The optimized program is ready to run What sorts of facilities are available at runtime

G1 Garbage Collector Details and Tuning. Simone Bordet

Java & Coherence Simon Cook - Sales Consultant, FMW for Financial Services

Robust Memory Management Schemes

The C4 Collector. Or: the Application memory wall will remain until compaction is solved. Gil Tene Balaji Iyengar Michael Wolf

Run-Time Environments/Garbage Collection

Garbage Collection. Akim D le, Etienne Renault, Roland Levillain. May 15, CCMP2 Garbage Collection May 15, / 35

A new Mono GC. Paolo Molaro October 25, 2006

The G1 GC in JDK 9. Erik Duveblad Senior Member of Technical Staf Oracle JVM GC Team October, 2017

Acknowledgements These slides are based on Kathryn McKinley s slides on garbage collection as well as E Christopher Lewis s slides

Automatic Garbage Collection

Habanero Extreme Scale Software Research Project

The Garbage-First Garbage Collector

CMSC 330: Organization of Programming Languages

Managed runtimes & garbage collection. CSE 6341 Some slides by Kathryn McKinley

Java Without the Jitter

Managed runtimes & garbage collection

Mark-Sweep and Mark-Compact GC

MEMORY MANAGEMENT HEAP, STACK AND GARBAGE COLLECTION

NUMA in High-Level Languages. Patrick Siegler Non-Uniform Memory Architectures Hasso-Plattner-Institut

Garbage collection. The Old Way. Manual labor. JVM and other platforms. By: Timo Jantunen

Implementation Garbage Collection

CMSC 330: Organization of Programming Languages. Memory Management and Garbage Collection

Do Your GC Logs Speak To You

Memory management has always involved tradeoffs between numerous optimization possibilities: Schemes to manage problem fall into roughly two camps

CMSC 330: Organization of Programming Languages

Finally! Real Java for low latency and low jitter

Java Memory Management. Märt Bakhoff Java Fundamentals

2011 Oracle Corporation and Affiliates. Do not re-distribute!

The Fundamentals of JVM Tuning

Performance of Non-Moving Garbage Collectors. Hans-J. Boehm HP Labs

Shenandoah: An ultra-low pause time garbage collector for OpenJDK. Christine Flood Roman Kennke Principal Software Engineers Red Hat

CS61C : Machine Structures

Understanding Java Garbage Collection

High Performance Managed Languages. Martin Thompson

CS577 Modern Language Processors. Spring 2018 Lecture Garbage Collection

Programming Language Implementation

Java Application Performance Tuning for AMD EPYC Processors

Understanding Java Garbage Collection

JVM Performance Tuning with respect to Garbage Collection(GC) policies for WebSphere Application Server V6.1 - Part 1

Kodewerk. Java Performance Services. The War on Latency. Reducing Dead Time Kirk Pepperdine Principle Kodewerk Ltd.

CS 4120 Lecture 37 Memory Management 28 November 2011 Lecturer: Andrew Myers

A JVM Does What? Eva Andreasson Product Manager, Azul Systems

Garbage Collection Techniques

CS Computer Systems. Lecture 8: Free Memory Management

Java Garbage Collection Best Practices For Tuning GC

JVM Performance Study Comparing Java HotSpot to Azul Zing Using Red Hat JBoss Data Grid

CSE P 501 Compilers. Memory Management and Garbage Collec<on Hal Perkins Winter UW CSE P 501 Winter 2016 W-1

CS 241 Honors Memory

Understanding Garbage Collection

Garbage-First Garbage Collection by David Detlefs, Christine Flood, Steve Heller & Tony Printezis. Presented by Edward Raff

Last week, David Terei lectured about the compilation pipeline which is responsible for producing the executable binaries of the Haskell code you

Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide. Release 10

Garbage Collection. Weiyuan Li

Lecture 15 Garbage Collection

Heap Management. Heap Allocation

Dynamic Storage Allocation

Dynamic Memory Allocation

Garbage Collection. Vyacheslav Egorov

Garbage Collection Algorithms. Ganesh Bikshandi

Garbage Collection (2) Advanced Operating Systems Lecture 9

CS 345. Garbage Collection. Vitaly Shmatikov. slide 1

Deallocation Mechanisms. User-controlled Deallocation. Automatic Garbage Collection

NG2C: Pretenuring Garbage Collection with Dynamic Generations for HotSpot Big Data Applications

JVM Performance Study Comparing Oracle HotSpot and Azul Zing Using Apache Cassandra

Run-time Environments -Part 3

High Performance Managed Languages. Martin Thompson

The Application Memory Wall

Generational Garbage Collection Theory and Best Practices

Low latency & Mechanical Sympathy: Issues and solutions

Parallel GC. (Chapter 14) Eleanor Ainy December 16 th 2014

Memory Management. Memory Management... Memory Management... Interface to Dynamic allocation

Understanding Java Garbage Collection

Pause-Less GC for Improving Java Responsiveness. Charlie Gracie IBM Senior Software charliegracie

Chapter 9 Real Memory Organization and Management

Chapter 9 Real Memory Organization and Management

Towards High Performance Processing in Modern Java-based Control Systems. Marek Misiowiec Wojciech Buczak, Mark Buttner CERN ICalepcs 2011

Automatic Memory Management

1. Mark-and-Sweep Garbage Collection

Java Performance Tuning From A Garbage Collection Perspective. Nagendra Nagarajayya MDE

A Tour to Spur for Non-VM Experts. Guille Polito, Christophe Demarey ESUG 2016, 22/08, Praha

The HALFWORD HEAP EMULATOR

Understanding Java Garbage Collection

Review. Partitioning: Divide heap, use different strategies per heap Generational GC: Partition by age Most objects die young

New Java performance developments: compilation and garbage collection

Understanding Java Garbage Collection

Transcription:

Garbage Collection (aka Automatic Memory Management) Douglas Q. Hawkins http://www.dougqh.net dougqh@gmail.com Why?

Leaky Abstraction 2 of 3 Optimization Flags Are For Memory Management Unfortunately, the biggest reason why we need to care about garbage collection is because it is the place where the abstract of the virtual machines leak the most. In fact, big data systems built on Java have to side-step the garbage collector. In part, this is because garbage collection techniques are just keeping up with the advances in hardware. The state of the art in garbage collection has to continue to evolve to handle the same things we struggle with multi-core, multi-threaded and also have to deal with the gory details of caches and memory latency and nonuniform memory access....but this is not a comprehensive talk about tuning for that I d refer you to the new book on Java Performance or the Sun Memory Management whitepaper.... but not about tuning per se...

HotSpot Collectors -XX:+UseSerialGC -XX:+UseConcMarkSweepGC -XX:+UseParallelOldGC -XX:+UseParNewGC -XX:+UseParallelGC HotSpot has bunch of different collectors, so I want you to come away from this talk understand why it has though different collectors. And, to have a basic understanding of theory behind those collectors, so that you know better how to tune them. Young Serial Parallel Parallel Scavenge Old Serial Old (Mark Compact) Concurrent Mark & Sweep Parallel Old (Mark Compact) Topics This talk will cover a broad range of topics: including fundamental concepts of garbage collection, specifics of allocation and garbage collection in different VMs. And, touch on alternatives to garbage collection. Basic Garbage Collection Strategies & Terminology Garbage Collection in HotSpot Garbage Collection in J9 and JRockit Alternatives to Garbage Collection Azul C4

Fundamentals Tasks for a Tracing GC Identify Live Objects Remove Dead Objects Optionally, Coalesce Free Space (Compaction) The fundamentals of a tracing GC are relatively straight-forward. Identify the live objects - whatever is not found to be alive must be dead. Remove the dead objects. Optionally, merge chunks of free space - possibly by compacting the live objects to be closer together.

Mark & Sweep Stack Frames Static Variables System.in System.out One the easiest to understand implementations is also one of the oldest: mark and sweep. This algorithm dates back 50 years to the earliest implementations of Lisp. Remarkably, variations of this algorithm remain useful today. Mark and sweep is a straight-forward implementation of the basic tracing idea. First, we start from a set of roots which include any active stack frames, static field references, among other things. From these roots, we identify objects that are used in the heap. After identifying the first level of objects, we follow references in those objects to the next set of objects, and so on. Whatever objects that we don't visit are garbage and can be swept away. NOTE: That the two objects in the lower right refer to each other, but are not reachable through the roots and can still be collected. (This is the main advantage of tracing collectors over reference counting.) Mark Compact The problem with mark & sweep is that it leaves wholes scattered throughout the heap. As we'll see in the next slide, this has some interesting implications for allocation. To get rid of the holes, we can use a variation on mark & sweep called mark compact. Mark compact is not just a sweep followed by a compact. The sweep and the compact steps are useful performed as a single step. The most basic way to perform compact is two finger compaction. In two finger compaction, one pointer starts from the left and another from the right. The pointer on the left identifies dead slots, the pointer on the right identifies live objects to relocate. The problem with this approach is that old and new objects end up mixed somewhat randomly in the heap. This hurts locality resulting in more cache misses.

Allocation How we garbage collect objects (deallocated) actually has a strong influence on how we allocate objects. If we've compacted our heap, then we can use a very simple allocation technique. We track just track a single pointer. If there is enough space between the pointer and the end of the heap, we have room to allocate. This technique is O(1) time and O(1) space. Because the technique involves incrementing a single pointer, it is called "bump the pointer" allocation. 4 8 If we have holes in the heap, then we have to maintain a free list. When we need to allocate, we traverse the list looking for a big enough whole in which to place our object. This technique is O(n) time and O(n) space. The simple free list mentioned above can lead to a lot of small blocks at the beginning of the free list that cannot contain the object being allocated. To combat this problem, we can use a segregated fits approach. Here we keep separate free lists for different block sizes. This approach is still O(n) time and O(n) space, but has better average case Copy Collector A slightly less obvious collection strategy is to use a copy collector. A copy collector works by making copies of the live objects in separate area of the heap. This is done by starting from the roots and copying the live objects over to a clean space. When complete the old space is completely empty and can be reclaimed enmass. Copying objects may seem wasteful particularly for large objects -- and it is, but as we'll see if most of the objects are not live that ends up being a non-issue. This process of moving survivors to another space is called evacuation. And, because, this approach involves two separate spaces this is sometimes called a semi-space collector. This type of collector is also sometimes called a scavenge collector. Then the objects they reference and so. As shown here, this is done breadth first. However, a breadth first approach poses problems for

Copy Collector A slightly less obvious collection strategy is to use a copy collector. A copy collector works by making copies of the live objects in separate area of the heap. This is done by starting from the roots and copying the live objects over to a clean space. When complete the old space is completely empty and can be reclaimed enmass. Copying objects may seem wasteful particularly for large objects -- and it is, but as we'll see if most of the objects are not live that ends up being a non-issue. This process of moving survivors to another space is called evacuation. And, because, this approach involves two separate spaces this is sometimes called a semi-space collector. This type of collector is also sometimes called a scavenge collector. Then the objects they reference and so. As shown here, this is done breadth first. However, a breadth first approach poses problems for Tracing Problem Random Walk of Heap Cache Hostile Bad Idea on Large Heap

Generational Hypothesis The problem with all the strategies discussed so far is that they require a random walk of the heap to identify live objects. Unforutnately, a random walk of the heap is extremely cache hostile. We could improve performance if we only walked part of the heap. Bytes Surviving Infants Fortunately, a simple and nearly universal observation allows us to do just that -- that observation - most objects either: die young or live forever. The chart shown here comes from a stereo-typical Java program. You can see a strong peak towards the short-lived portion of the spectrum. http://www.devx.com/java/article/21977 http://www.ibm.com/developerworks/java/library/j-jtp09275.html http://java.sun.com/j2se/reference/whitepapers/ memorymanagement_whitepaper.pdf Bytes Allocated Generational Stack Frames Young The problem with all the strategies discussed so far is that they require a random walk of the heap to identify live objects. Unforutnately, a random walk of the heap is extremely cache hostile. We could improve performance if we only walked part of the heap. Static Variables System.in System.out Old / Tenured Fortunately, a simple and nearly universal observation allows us to do just that -- that observation - most objects either: die young or live forever. The chart shown here comes from a stereo-typical Java program. You can see a strong peak towards the short-lived portion of the spectrum. http://www.devx.com/java/article/21977 http://www.ibm.com/developerworks/java/library/j-jtp09275.html http://java.sun.com/j2se/reference/whitepapers/ memorymanagement_whitepaper.pdf

Remembered Set Stack Frames Young...but how does separating young and old help us scan the heap less often? A "remembered set" is used to keep track of references between the generations. This remembered set is kept up to date through the use of a write barrier. Whenever, a reference is modified if the object being updated is in the old generation, the remembered set is updated. Static Variables System.in System.out Old During most collections just the young generation is "condemned", at this time, the remembered set effectively acts as an extra set of roots for the young generation. Whether we need a remembered set for the old generation depends on whether the old generation can be collected independently from the young generation. If it can be collected independently, we'd need another remembered set to track references from young to old. In general for n- regions, we need n*(n-1) remembered sets - i.e. O(n^2). As an benefit, we can also use different collection strategies for the two distinct generations / regions. Remembered Set Stack Frames Young...but how does separating young and old help us scan the heap less often? A "remembered set" is used to keep track of references between the generations. This remembered set is kept up to date through the use of a write barrier. Whenever, a reference is modified if the object being updated is in the old generation, the remembered set is updated. Static Variables System.in System.out Old During most collections just the young generation is "condemned", at this time, the remembered set effectively acts as an extra set of roots for the young generation. Whether we need a remembered set for the old generation depends on whether the old generation can be collected independently from the young generation. If it can be collected independently, we'd need another remembered set to track references from young to old. In general for n- regions, we need n*(n-1) remembered sets - i.e. O(n^2). As an benefit, we can also use different collection strategies for the two distinct generations / regions.

GC in Java VMs HotSpot Garbage Collector Young Generation Eden S0 Old Generation S1 Now, that you know the core concepts let's talk about memory management in HotSpot. As you'll see, HotSpot uses a generational heap with a slight variation on the copy/semi-space collector for the young generation, and a couple different options on how to collect the old generation. http://download.oracle.com/javase/1.5.0/docs/guide/vm/gcergonomics.html http://java.sun.com/j2se/reference/whitepapers/ memorymanagement_whitepaper.pdf Different heap size defaults in Java 6 - lesser of 1/4 of physical or 1GB Adaptive sizing - now the default with -XX:+UseParallelGC (starting with 1.5?)

Young vs Tenured Collections Bytes Surviving Young Tenured Looking at the graph from earlier, minor collections handle the large peak at the beginning and the small bump that follows. The major collections cleaned up what reamins thereafter. The small peak at the far right is immortals objects which even the major collections will eventually ignore because of the "dense prefix" optimization. http://java.sun.com/docs/hotspot/gc/ http://www.devx.com/java/article/21977 http://www.ibm.com/developerworks/java/library/j-jtp09275.html http://java.sun.com/j2se/reference/whitepapers/ memorymanagement_whitepaper.pdf Bytes Allocated Which Tracing Strategy? Liveness Strategy Low (Young Region) Copy High (Tenured Region) Mark & Sweep OR Mark Compact

Object Allocation TLAB Young Generation Eden S0 Old Generation S1 First, we'll look at object allocation in HotSpot... HotSpot calls the allocation area Eden and uses a "pump the pointer" approach to allocate; however, it has an optimization to improve multithreaded performance. If HotSpot used a single pointer, that pointer would always need to be synchronized between threads. Instead each thread requests a thread local allocation buffer (TLAB), objects for each thread are allocated within the TLAB using a "bump pointer technique" with a thread local pointer. As of Java 5, TLABs are dynamically sized by HotSpot. http://blogs.sun.com/jonthecollector/entry/the_real_thing http://blogs.sun.com/jonthecollector/entry/a_little_thread_privacy_please Minor Collection TLAB Young Generation Eden Once we run out of space in "Eden", we have to collect the young generation -- HotSpot calls this a "minor" collection. When collecting the young generation, HotSpot evacuates live objects from Eden into one of two survivor spaces (S0 and S1). At the start of collection one of the survivor spaces, S0 or S1 will always be empty. Objects from the other survivor space that are still alive will also be evacuated. S0 Old Generation 1 2 S1 At the end of the minor collection, Eden and one of survivor spaces will be completely reclaimed. By doing this the pump pointer technique can be used for allocation in Eden, but also when relocating objects to a survivor space during a minor collection. Eventually, objects that survive enough minor collections will be promoted to the old generation. http://www.fasterj.com/articles/g1.shtml http://java.sun.com/docs/hotspot/gc1.4.2/faq.html http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html

Major Collection Young Generation Eden S0 S1 For the old generation, we can choose to use either mark compaction or mark and sweep. As we'll see when we talk about parallelism and concurrency, each of these approaches have their pros and cons. http://www.devx.com/java/article/21977/0 http://www.austinjug.org/presentations/jdk6perfupdate_dec2009.pdf http://java.sun.com/j2se/reference/whitepapers/ memorymanagement_whitepaper.pdf Old Generation Permanent Generation Young Generation Eden HotSpot has one more generation -- the permanent generation where it allocates classes. In newer versions of HotSpot, the permanent generation isn't really permananent, but it is still close. If even one object remains alive from a class, then all classes from that ClassLoader will stay in the permanent generation. S0 Old Generation S1 http://opensource.atlassian.com/confluence/spring/pages/ viewpage.action?pageid=2669 http://dow.ngra.de/2009/06/15/classloaderlocal-how-to-avoid-classloaderleaks-on-application-redeploy/ Permanent Generation C C C C C C C C Bootstrap App Server Web Application

Demo https://visualvm.dev.java.net/ https://visualvm.dev.java.net/plugins.html Tuning Steady State Newer JVMs can adaptively tune, but you may not want to rely on that.

Adaptive Tuning Newer JVMs can automatically tune, but you may not want to rely on that. -XX:MaxGCPauseMillis -XX:GCTimeRatio Meets these goals by adjusting the heap size. 8x Basic Principles Maximize Collection during Minor GCs Avoid Major GCs at much as possible Promote as little as possible Maximize Available Memory Adjust for 2 of 3 GC Goals Throughput Latency Footprint

Set Xms = Xmx initial heap size max heap size Stops region resizing which would require a full GC 3-4x Young (Xmn): 1-1.5x Old: 2-3x Set XX:PermSize = XX:MaxPermSize Again, stops region resizing which would require a full GC 1.2-1.5x

GC Choices Serial VS. Parallel Stop the World Compacting VS. Concurrent Non-compacting Full VS. Incremental Serial Parallel Earlier HotSpot VMs, used a serial garbage collection for both the young and old generation. Newer VMs can used multiple threads simultaneously to achieve parallel collection; however, that does not mean that they do not stop the world. http://www.austinjug.org/presentations/jdk6perfupdate_dec2009.pdf Stop the World! Application Thread GC Thread

Why Stop the World? 0x04 0x0C So, why do we have to "stop the world"? The problem is the need to move/relocate objects. Unlike what you might expect, the problem is not the need to copy when relocating; it's the need to update all references. Unfortunately, those references from roots and other objects need to all be updated at once which requires stopping the application temporarily. If we don't relocate, we can around this problem. 0x04 0x0C 0x04 0x0C Parallel Mark Compact Concurrent Mark & Sweep This is where concurrent mark & sweep (CMS) comes in. By not relocating objects, concurrent mark and sweep can be concurrent - i.e. not stop the world. To do this, it tracks object references as your application runs. This phase is called "concurrent marking". Concurrent Marking Remark Concurrent Sweep Before collecting garbage, it has to make sure it's marking is completely up-todate, so stops the world briefly to perform a "re-mark" phase. The length of this pause will be proportional to the number of reference mutations being performed by your application. With re-mark complete, HotSpot now knows which objects are no longer being used and can collect while your application continues to run. http://www.devx.com/java/article/21977/0/page/3 http://www.austinjug.org/presentations/jdk6perfupdate_dec2009.pdf Application Thread GC Thread

HotSpot Collectors -XX:+UseSerialGC Young Old -XX:+UseParNewGC Serial Serial Old (Mark Compact) -XX:+UseConcMarkSweepGC -XX:+UseParallelOldGC Parallel Concurrent Mark & Sweep -XX:+UseParallelGC Parallel Scavenge Parallel Old (Mark Compact) So, what are your options for garbage collection in HotSpot. First, you can use serial collection for both young old, but there's little reason to do so. You can also use parallel just for the young generation, but again there's little reason to. You can used concurrent mark & sweep for the old generation which uses parallel new to help with some of the book keeping. Unfortunately, when it needs to compact, CMS falls back on serial old. The default is to use parallel young and parallel old (at least until Java 7). http://www.petefreitag.com/articles/gctuning/ http://blogs.sun.com/jonthecollector/entry/our_collectors http://openjdk.java.net/groups/hotspot/docs/hotspotglossary.html Throughput vs Latency Your choice in collector mostly comes down to whether throughput or latency is more important. If you are running a batch processing system, you might prefer throughput. You'll have longer pauses, but overall the job will get done faster. In this case, you want to use the default parallel young and parallel old. If you are running a web site, then long pauses may be unacceptable. In that case, you'd want to use CMS, but if you have to be careful that your application does not fall back to serial compact which could result in a really long pause. http://www.austinjug.org/presentations/jdk6perfupdate_dec2009.pdf Application Thread GC Thread

If Latency is Too High, Switch to ConcMarkSweep CMS kicks in when old generation is 65% full. Increase Old Generation an additional 25-30% When compaction is needed it is serial, so avoid compaction at all costs! GCs in Other JVMs

J9 Nursery Allocate Tenured C Survivor Now, that we've talked about HotSpot, let's look at how other JVMs differ. IBM's J9 can use either continuous heap or generational heap. When using generational mode, J9 uses a a copying semi-space collector for the young generation. Alternating the roles of the Allocate and Survivor regions between collections. The tenured distribution is collected through incremental mark compaction. Unlike HotSpot, J9 does not have a permanent generation; however, it does assume that classes will typically live an extend period of time -- so it allocates directly in the Tenured region. http://blog.dynatrace.com/2011/05/11/how-garbage-collection-differs-inthe-three-big-jvms/ http://docs.oracle.com/cd/e13150_01/jrockit_jvm/jrockit/geninfo/diagnos/ memman.html JRockit Nursery Keep Area Tenured C C Survivor C Like J9, JRockit can also use a non-generational heap; however, even when operating in generational mode JRockit uses an extreme simple tenuring policy. In JRockit, needs objects are allocated in a "Keep Area". "Keep Area" objects are not considered (at all) for collection during GC. Instead objects in the "Keep Area" are evacuated into the "Survivor" region. During GC objects in the "Survivor" region that are still alive are promoted to the "Tenured" region. In effect, this means that JRockit always has tenuring promotion value of 2. Like J9, JRockit uses incremental mark compact to collect the Tenured region. However, unlike J9, JRockit allocates classes in the same fashion as regular objects. http://blog.dynatrace.com/2011/05/11/how-garbage-collection-differs-inthe-three-big-jvms/ http://docs.oracle.com/cd/e13150_01/jrockit_jvm/jrockit/geninfo/diagnos/ memman.html

Hybrid Mark Sweep & Copy To achieve incremental mark compact, J9 and JRockit use a hybrid mark sweep and copy approach. Like concurrent mark & sweep, the mark & sweep approach will causes fragmentation in the heap. To remove the fragmentation, incremental compaction is achieving through copying. Here a "To" region in the heap is identified that proceeds a "From" region. Live objects in the "From" region are then evacuated into the "To" region. In this way, sliding compaction can be distributed over several garbage collection cycles. To From New GCs in Java VMs

G1:Garbage First & Balanced To combat the limitations of the concurrent HotSpot collectors, Java 7 (and 6) include G1 - the Garbage First collector. Not to be outdone, J9 includes a very similar collector dubbed "Balanced GC". These collectors work by dividing the heap into a large number of uniformly sized regions. Unfortunately, of the O(n^2) cost in tracking references between regions there is a limited on how many regions can be used. For this reason, Balanced GC aims to have between 1024 and 2047 regions regardless of the heap size. http://developers.sun.com/learning/javaoneonline/2008/pdf/ts-5419.pdf http://www.ibm.com/developerworks/websphere/techjournal/ 1108_sciampacone/1108_sciampacone.html G1 & Balanced GC Let's look at object allocation and collection in G1 and Balanced GC... Unlike the generational collectors, we've seen previously. Regions in G1 are not always for allocation, young objects, or old objects. How each reason is used will change over the life of the application. Objects will be allocated in a previously empty region. To better deal with NUMA, Balanced GC biases regions to different processors. Like CMS, the utilization of each region is tracked concurrently. http://developers.sun.com/learning/javaoneonline/2008/pdf/ts-5419.pdf Unused Young Old

G1 - Minor Collection When performing a minor GC, G1 picks a subset of young regions to collect. These are picked according to the amount of garbage present. If region turns out to be all garbage then the whole region can be reclaimed immediately -- thus "garbage first". Otherwise, the region is condemned and objects are evacuated to a previously unused region. Unused Young Old G1 - Major Collection For major collection, G1 picks some a sub-set of young and old regions. Here again objects are evacuated to previous empty region. Because of the evacuation to other regions, G1 and Balanced GC still have to stop the world, but focusing on regions that are mostly garabge, they aim to make the evacuation pauses as short as possible. Unused Young Old

Azul C4 Continuously Concurrent Compacting Collector There is one more server class JVM, that we have not discussed -- Azul. Azul was formed by former Sun staff that worked on HotSpot. They set out to design JVM with special to features to better handle large server applications. Early versions of Azul, only ran on custom hardware, but now they can run on (mostly) stock Linux. To From Azul has a truly pauseless GC -- i.e. fully concurrent. To do this, they uses incremental compaction similar to J9 and JRockit, but with an added twist. A read barrier is used to detect when an out of date reference is being followed. If that happens, a mini GC happens to complete the relocation of that object, so that the application thread may continue on its way. http://www.azulsystems.com/products/zing/c4-java-garbage-collector-wp Despite all the advances in GC, sometimes we need to use other options to get around GC limitations. Alternatives to Hard References & GC

WeakReference WeakReference<Foo> fooref = new WeakReference<Foo>(foo); Foo foo = fooref.get(); Sometimes, there's a need to cache an extra piece information as long as some related object is alive. To do that, we can use a weak reference. A WeakReference works by pointing to an object as long as at least one hard reference to the same object continues to exist. After that, the GC can collect the object and the WeakReference will return null. WR SoftReference SoftReference<Foo> fooref = new SoftReference<Foo>(foo); Foo foo = fooref.get(); Similar to a WeakReference, a SoftReference may also be cleaned up by the GC. However, this time no hard references are required. The SoftReference acts as a hint to the GC that is okay to clean up the reference is necessary, but that you'd prefer to keep it around. SR Garbage Collected if Low on Space

Be Careful With References Reference<User> ref =... if ( ref.get()!= null ) { System.out.println(ref.get().getName()); } Because the GC is free to remove the underlying object whenever, all code using Reference objects is inherently multi-thread. This means you need to be careful not to call Reference.get() twice in the same method. In the example above, the second call to Reference.get() could return null causing the code to raise a NullPointerException if the GC kicked after the if. Possible NullPointerException Reference<User> ref =... User user = ref.get(); if ( user!= null ) { System.out.println(user.getName()); } Guava MapMaker & CacheBuilder ConcurrentMap<Key, Graph> graphs = new MapMaker().concurrencyLevel(4).weakKeys().maximumSize(10000).expireAfterWrite(10, TimeUnit.MINUTES).makeComputingMap( new Function<Key, Graph>() { public Graph apply(key key) { return createexpensivegraph(key); } }); The main reason to use Reference objects is for caches. Because Reference classes tend to be a bit tricky to use, I d recommend using Guava s MapMaker or CacheBuilder when working with references. (NOTE: Unlike Java s built-in WeakHashMap, MapMaker uses with weakkeys() uses referential equals not Object.equals.) http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/ common/collect/mapmaker.html http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/ common/cache/cachebuilder.html

PhantomReference X PR There is one more reference type that serves as a replacement for finalize. Using a PhantomReference with a ReferenceQueue, you can achieve finalization without having to worry about the finalize s shortcomings... - multi-threaded - no order guarantee - object resurrection ReferenceQueue Direct ByteBuffers ByteBuffer buffer = ByteBuffer.allocateDirect(...); If you are dealing with truly gigantic amounts of memory in Java, GC can become a real problem. To get around this, you can use unmanaged memory in the form of direct ByteBuffers. When using ByteBuffer, you typically allocate a slab of memory in a buffer and then serialize objects to store them in the buffer. This means there is some overhead to serialize / deserialize an object when moving to/from normal heap. Cassandra, Apache HBase, and Terracotta all use direct ByteBuffers to avoid issues with Full GC.

Additional Reading Java Performance By Charlie Hunt and Binu John http://www.amazon.com/java-performance-charlie-hunt/ Everything I Ever Learned About JVM Performance Tuning By Attila Szegedi http://www.infoq.com/presentations/jvm-performance-tuning-twitter Memory Management in the HotSpot Java Virtual Machine http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf The Garbage Collection Handbook By Richard Jones, Antony Hoskin, Eliot Moss http://www.amazon.com/the-garbage-collection-handbook-management/ Q&A