4 Understanding Memory Management

Memory management is the process of removing unused objects from the heap, to make memory available for new objects. This chapter presents basic memory management concepts and explains how object allocation and garbage collection work in the Oracle JRockit JVM.

This chapter contains information about the following topics:

4.1 Heap and Nursery

Java objects reside in an area called the heap, a section of the memory stack that is created when the JVM starts. The heap can grow or shrink while the application runs.

When the heap becomes full, garbage is collected: The JRockit JVM identifies memory spaces that contain objects that are being used (live objects). It then reclaims the memory spaces that do not contain live objects, and makes those spaces available for allocation to new objects.

Note:

The JRockit JVM uses more memory than the heap; Java methods, thread stacks, native handles, and JVM internal data structures are allocated in a memory space that is separate from the heap.

The heap is sometimes divided into two generations: a nursery (or young space) and an old space. The nursery is a part of the heap reserved for allocating new objects. When the nursery becomes full, garbage is collected by running a special young collection, through which all objects that have lived long enough in the nursery are promoted (moved) to the old space, freeing up the nursery for more object allocation. When the old space is full, garbage is collected there—a process called old collection.

Note:

At times, during a young collection, there might not be enough memory left in the old space to promote objects from the nursery. Until memory becomes available in the old space, objects that are identified for promotion to the old space are instead promoted within the nursery, resulting in a fragmented nursery. This situation is known as promotion failure.

In R28.1, the JRockit JVM assesses the likelihood of an upcoming young collection resulting in a promotion failure, and prevents it by triggering an old collection.

A multigenerational heap helps reduce the overall garbage collection time. Most objects allocated in the heap are short-lived. The young collection quickly finds newly allocated objects in the nursery that are still being used and moves them out of the nursery to the old space. Typically, a young collection frees a given amount of memory much faster than an old collection or a garbage collection of a single-generational heap (a heap without a nursery).

A part of the nursery is reserved as a keep area, for holding objects that were allocated just before a young collection started. These objects are not garbage collected until the next young collection.

4.2 Object Allocation

During object allocation, the JRockit JVM distinguishes between small and large objects. The limit for when an object is considered large depends on the heap size, the garbage collection strategy, and the platform being used, but is usually between 2 and 128 KB. For more information, see the documentation for the -XXtlaSize command-line option in the Oracle JRockit Command-Line Reference.

Small objects are allocated in thread local areas (TLAs), which are free chunks of memory reserved from the heap and given to a Java thread for exclusive use. The thread can then allocate objects in its TLA without synchronizing with other threads. When the TLA becomes full, the thread requests for a new TLA. The TLAs are reserved in the nursery, if one exists; otherwise, they are reserved anywhere on the heap.

Objects that are larger than the TLA size are allocated directly on the heap. Allocation of large objects requires more synchronization among the Java threads; the JRockit JVM uses a system of caches of free chunks of different sizes to reduce the need for synchronization and to improve the allocation speed.

4.3 Garbage Collection

Garbage collection frees space in the heap for allocating new objects.

The following topics describe how garbage collection works in the JRockit JVM.

4.3.1 Mark-and-Sweep Model

The JRockit JVM uses the mark-and-sweep garbage collection model to perform garbage collections of the whole heap.

  • During the mark phase, all objects that can be reached directly from Java threads, native handles, and other root sources; objects that can be reached from the first set of objects; and so on are marked as being used (live objects). The remaining objects are considered garbage.

  • During the sweep phase, the heap is traversed to identify the gaps between the live objects. The gaps are recorded in a free list and are made available for new object allocation.

The JRockit JVM provides two improved strategies of the mark-and-sweep model: mostly concurrent and parallel. You can mix the two strategies; for example, you can run the mostly concurrent mark with a parallel sweep.

Mostly Concurrent Mark-and-Sweep Strategy

The mostly concurrent mark-and-sweep strategy (often called concurrent garbage collection) allows the Java threads to continue running during large portions of the garbage collection process. The threads must, however, be stopped a few times for synchronization.

The mostly concurrent mark phase is divided into four stages:

  • Initial marking

    The root set of live objects is identified. This is done while the Java threads are paused.

  • Concurrent marking

    The references from the root-set are followed to find and mark the remaining live objects in the heap. This is done while the Java threads run.

  • Precleaning

    Changes in the heap during the concurrent mark phase are identified and any additional live objects are found and marked. This is done while the Java threads run.

  • Final marking

    Changes during the precleaning phase are identified and any additional live objects are found and marked. This is done while the Java threads are paused.

The mostly concurrent sweep phase consists of four stages:

  • Sweeping one half of the heap

    This occurs while the Java threads run; object allocation can continue in the part of the heap that is currently not being swept.

  • A short pause to switch halves

  • Sweeping the other half of the heap

    This is done while the Java threads run; object allocation can continue in the part of the heap that was swept first.

  • A short pause for synchronization and recording statistics

Parallel Mark-and-Sweep Strategy

The parallel mark and sweep strategy (also called the parallel garbage collector) uses all available CPUs in the system for performing the garbage collection as fast as possible. All Java threads are paused during the parallel garbage collection.

4.3.2 Generational Garbage Collection

When a nursery exists (as described in Section 4.1, "Heap and Nursery"), its garbage is collected with a special garbage collection called a young collection. A garbage collection strategy that uses a nursery is called generational garbage collection.

The young collector used in the JRockit JVM identifies and promotes all live objects in the nursery that are outside the keep area to the old space. This work is done in parallel by using all available CPUs. The Java threads are paused during the young collection.

4.3.3 Garbage Collection Modes

The JRockit JVM automatically selects a garbage collection strategy that optimizes the application throughput.

The following garbage collection modes are available:

  • throughput (default mode): Optimizes the garbage collector for maximum application throughput

  • pausetime: Optimizes the garbage collector for short and even pause times

  • deterministic (only available as a part of Oracle JRockit Real Time): Optimizes the garbage collector for very short and deterministic pause times

For more information, see "Selecting and Tuning a Garbage Collector" in the Oracle JRockit Performance Tuning Guide.

4.4 Compaction

After a garbage collection, the heap may become fragmented. Numerous free spaces exist, but each free space is small, making allocation of large objects difficult or impossible. Free spaces that are smaller than the minimum TLA size cannot be used and the garbage collector discards them as dark matter until a future garbage collection frees space next to them, creating a space large enough for a TLA.

To reduce fragmentation, the JRockit JVM compacts a part of the heap at every garbage collection (old collection). Compaction moves objects closer and further down in the heap, creating larger free areas near the top of the heap. The size (and position) of the compaction area and the compaction method are selected by advanced heuristics, depending on the garbage collection mode used.

Compaction is performed at the beginning of or during the sweep phase and while all Java threads are paused.

For information about how to tune compaction, see "Tuning the Compaction of Memory" in the Oracle JRockit Performance Tuning Guide.

External and Internal Compaction

The JRockit JVM uses two compaction methods: external compaction and internal compaction.

External compaction moves (evacuates) the objects within the compaction area to free positions outside the compaction area and as far down in the heap as possible. Internal compaction moves the objects within the compaction area as far down in the compaction area as possible, moving them closer.

The JVM selects a compaction method depending on the current garbage collection mode and the position of the compaction area. External compaction is typically used near the top of the heap, while internal compaction is used near the bottom, where the density of objects is higher.

Compaction Area Size and Location

The size and location of the compaction area depends on the garbage collection mode and the current state of the Java heap.

If the number of references to objects within an area (object density) is high, the compaction area size is small. Typically the object density is higher toward the bottom of the heap than toward the top, except at the very top of the heap, which contains recently allocated objects. So the compaction areas are usually smaller near the bottom of the heap than at the top of the heap.