• No results found

Two-region collectors

Two-region collectors

“When faced with two equally tough choices,

most people choose the third choice: to not choose.” 

THE JAVA GARBAGE COLLECTION MINI-BOOK

26

The .NET CLR comes with two collectors: a client one and a server one. OpenJDK and the Oracle JDK, on the other hand, each come with four, and there are a number of other collectors available from different JVM providers.

Since Java 2 SE 5.0, default values for the garbage collector, heap size, and HotSpot virtual machine (client or server) are automatically chosen based on the platform and operating system on which the application is running. The JVM will often do a pretty decent job of selecting a garbage collector for you and it may be that you never have to consider the choices that it makes. You can, however, select the algorithm that the  JVM is using for your program. Knowing what each collector does and how it works may help you in choosing the most appropriate one for your needs, though benchmarking is also important.

If you don’t know which collector you are running then the following program will show you:

import java.lang.management.GarbageCollectorMXBean ; import java.lang.management.ManagementFactory ;

import java.util.List;

public class GCInformation {

public static void main(String[] args) { List<GarbageCollectorMXBean > gcMxBeans =

  ManagementFactory.getGarbageCollectorMXBeans (); for (GarbageCollectorMXBean gcMxBean : gcMxBeans) {

System.out.println(gcMxBean.getName()); }

} }

This will output the younger generation first and show something like:

PS Scavenge PS MarkSweep

PS Scavenge is the parallel Eden/survivor space collector. PS MarkSweep is the parallel old-generation collector (not the same as a concurrent collector).

CMS will show: ParNew ConcurrentMarkSweep G1 will output: G1 Young Generation G1 Old Generation

Heap structure

The collectors we’ll look at in this part of the book divide the heap into two regions — young/new and tenured — to exploit the weak generational hypothesis.

Eden is the region where most objects are initially allocated. The survivor spaces are a temporary store for objects that have survived a collection of the Eden space. Collectively, Eden and the survivor spaces are known as the “young” or “new” generation.

The action of promotion is called a “minor GC event” and the collection is triggered when Eden becomes full. Promotion is done by copying all the live objects in the new generation to either a survivor space or the tenured space as appropriate. Copying to the tenured space is known as “promotion” or “tenuring”.

Promotion occurs for objects that are sufficiently old (– XX:MaxTenuringThreshold) or when

the survivor space overflows. By doing this, we keep the assumption about the young generation true; the objects in the young generation will die young, because those that don’t will be promoted. To allow a degree of resizing of the pools without having to move everything, there are also two reserved areas (sometimes called virtual spaces) between the two heap spaces.

THE JAVA GARBAGE COLLECTION MINI-BOOK

28

PermGen

Prior to Java 8, HotSpot also had a permanent generation (“PermGen”) contiguous with the Java heap in which the runtime stored objects that it believed were effectively immortal, along with per-class metadata such as hierarchy information, method data, stack and variable sizes, the runtime constant pool, resolved symbolic reference, and Vtables.

Figure 5: PermGen moves to Metaspace 

Unfortunately, many of the working assumptions behind PermGen are incorrect, particularly now that so many applications make use of custom class loaders. In Java 7, strings were moved from PermGen to tenured, and in Java 8 the permanent generation is no more, with the metadata moved to native memory in an area known as “Metaspace”.

The move to Metaspace was necessary since the PermGen was really hard to tune. One problem was that its size was limited based on -XX:MaxPermSize. This had to be set on the command line before starting the JVM or it would default to 64 MB (85 MB for 64-bit scaled pointers). Sizing depended on a lot of factors, such as the total number of classes, the size of the constant pools, size of methods, etc., and was notoriously difficult. By contrast, the class metadata is now allocated out of native memory, which means that the max available space is the total available system memory.

The collection of the permanent generation was tied to the collection of the old generation, so whenever either was full, both the permanent

generation and the old generation would be collected. If the class’s metadata size was beyond the bounds of -XX:MaxPermSize, your application ran out of memory. There was a possibility that the metadata could move with every full garbage collection.

From an implementation standpoint, each garbage collector in HotSpot needed specialised code for dealing with metadata in the PermGen. Writing for InfoQ, Monica Beckwith1  pointed out that “detaching metadata from PermGen not only allows the seamless management of Metaspace, but also allows for improvements such as simplification of full garbage collections and future concurrent deallocation of class metadata.” Most other commercial collectors also treat all long-living objects as tenured.

Related documents